provision_handler.go 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  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/analytics"
  8. "github.com/porter-dev/porter/internal/forms"
  9. "github.com/porter-dev/porter/internal/kubernetes"
  10. "github.com/porter-dev/porter/internal/kubernetes/provisioner"
  11. "github.com/porter-dev/porter/internal/models"
  12. "github.com/porter-dev/porter/internal/adapter"
  13. )
  14. // HandleProvisionTestInfra will create a test resource by deploying a provisioner
  15. // container pod
  16. func (app *App) HandleProvisionTestInfra(w http.ResponseWriter, r *http.Request) {
  17. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  18. if err != nil || projID == 0 {
  19. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  20. return
  21. }
  22. form := &forms.CreateTestInfra{
  23. ProjectID: uint(projID),
  24. }
  25. // decode from JSON to form value
  26. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  27. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  28. return
  29. }
  30. // convert the form to an aws infra instance
  31. infra, err := form.ToInfra()
  32. if err != nil {
  33. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  34. return
  35. }
  36. // handle write to the database
  37. infra, err = app.Repo.Infra.CreateInfra(infra)
  38. if err != nil {
  39. app.handleErrorDataWrite(err, w)
  40. return
  41. }
  42. _, err = app.ProvisionerAgent.ProvisionTest(
  43. uint(projID),
  44. infra,
  45. *app.Repo,
  46. provisioner.Apply,
  47. &app.DBConf,
  48. app.RedisConf,
  49. app.ServerConf.ProvisionerImageTag,
  50. app.ServerConf.ProvisionerImagePullSecret,
  51. )
  52. if err != nil {
  53. infra.Status = models.StatusError
  54. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  55. app.handleErrorInternal(err, w)
  56. return
  57. }
  58. app.Logger.Info().Msgf("New test infra created: %d", infra.ID)
  59. w.WriteHeader(http.StatusCreated)
  60. infraExt := infra.Externalize()
  61. if err := json.NewEncoder(w).Encode(infraExt); err != nil {
  62. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  63. return
  64. }
  65. }
  66. // HandleDestroyTestInfra destroys test infra
  67. func (app *App) HandleDestroyTestInfra(w http.ResponseWriter, r *http.Request) {
  68. // get path parameters
  69. infraID, err := strconv.ParseUint(chi.URLParam(r, "infra_id"), 10, 64)
  70. if err != nil {
  71. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  72. return
  73. }
  74. // read infra to get id
  75. infra, err := app.Repo.Infra.ReadInfra(uint(infraID))
  76. if err != nil {
  77. app.handleErrorDataRead(err, w)
  78. return
  79. }
  80. // launch provisioning destruction pod
  81. agent, err := kubernetes.GetAgentInClusterConfig()
  82. if err != nil {
  83. infra.Status = models.StatusError
  84. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  85. app.handleErrorDataRead(err, w)
  86. return
  87. }
  88. // mark infra for deletion
  89. infra.Status = models.StatusDestroying
  90. infra, err = app.Repo.Infra.UpdateInfra(infra)
  91. if err != nil {
  92. app.handleErrorDataWrite(err, w)
  93. return
  94. }
  95. _, err = agent.ProvisionTest(
  96. infra.ProjectID,
  97. infra,
  98. *app.Repo,
  99. provisioner.Destroy,
  100. &app.DBConf,
  101. app.RedisConf,
  102. app.ServerConf.ProvisionerImageTag,
  103. app.ServerConf.ProvisionerImagePullSecret,
  104. )
  105. if err != nil {
  106. app.handleErrorInternal(err, w)
  107. return
  108. }
  109. app.Logger.Info().Msgf("Test infra marked for destruction: %d", infra.ID)
  110. w.WriteHeader(http.StatusOK)
  111. }
  112. // HandleProvisionAWSECRInfra provisions a new aws ECR instance for a project
  113. func (app *App) HandleProvisionAWSECRInfra(w http.ResponseWriter, r *http.Request) {
  114. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  115. if err != nil || projID == 0 {
  116. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  117. return
  118. }
  119. form := &forms.CreateECRInfra{
  120. ProjectID: uint(projID),
  121. }
  122. // decode from JSON to form value
  123. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  124. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  125. return
  126. }
  127. // validate the form
  128. if err := app.validator.Struct(form); err != nil {
  129. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  130. return
  131. }
  132. // convert the form to an aws infra instance
  133. infra, err := form.ToInfra()
  134. if err != nil {
  135. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  136. return
  137. }
  138. // handle write to the database
  139. infra, err = app.Repo.Infra.CreateInfra(infra)
  140. if err != nil {
  141. app.handleErrorDataWrite(err, w)
  142. return
  143. }
  144. awsInt, err := app.Repo.AWSIntegration.ReadAWSIntegration(infra.AWSIntegrationID)
  145. if err != nil {
  146. infra.Status = models.StatusError
  147. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  148. app.handleErrorDataRead(err, w)
  149. return
  150. }
  151. // launch provisioning pod
  152. _, err = app.ProvisionerAgent.ProvisionECR(
  153. uint(projID),
  154. awsInt,
  155. form.ECRName,
  156. *app.Repo,
  157. infra,
  158. provisioner.Apply,
  159. &app.DBConf,
  160. app.RedisConf,
  161. app.ServerConf.ProvisionerImageTag,
  162. app.ServerConf.ProvisionerImagePullSecret,
  163. )
  164. if err != nil {
  165. infra.Status = models.StatusError
  166. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  167. app.handleErrorInternal(err, w)
  168. return
  169. }
  170. app.Logger.Info().Msgf("New aws ecr infra created: %d", infra.ID)
  171. w.WriteHeader(http.StatusCreated)
  172. infraExt := infra.Externalize()
  173. if err := json.NewEncoder(w).Encode(infraExt); err != nil {
  174. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  175. return
  176. }
  177. }
  178. // HandleDestroyAWSECRInfra destroys ecr infra
  179. func (app *App) HandleDestroyAWSECRInfra(w http.ResponseWriter, r *http.Request) {
  180. // get path parameters
  181. infraID, err := strconv.ParseUint(chi.URLParam(r, "infra_id"), 10, 64)
  182. if err != nil {
  183. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  184. return
  185. }
  186. // read infra to get id
  187. infra, err := app.Repo.Infra.ReadInfra(uint(infraID))
  188. if err != nil {
  189. app.handleErrorDataRead(err, w)
  190. return
  191. }
  192. awsInt, err := app.Repo.AWSIntegration.ReadAWSIntegration(infra.AWSIntegrationID)
  193. form := &forms.DestroyECRInfra{}
  194. // decode from JSON to form value
  195. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  196. infra.Status = models.StatusError
  197. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  198. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  199. return
  200. }
  201. // validate the form
  202. if err := app.validator.Struct(form); err != nil {
  203. infra.Status = models.StatusError
  204. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  205. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  206. return
  207. }
  208. // launch provisioning destruction pod
  209. // mark infra for deletion
  210. infra.Status = models.StatusDestroying
  211. infra, err = app.Repo.Infra.UpdateInfra(infra)
  212. if err != nil {
  213. app.handleErrorDataWrite(err, w)
  214. return
  215. }
  216. _, err = app.ProvisionerAgent.ProvisionECR(
  217. infra.ProjectID,
  218. awsInt,
  219. form.ECRName,
  220. *app.Repo,
  221. infra,
  222. provisioner.Destroy,
  223. &app.DBConf,
  224. app.RedisConf,
  225. app.ServerConf.ProvisionerImageTag,
  226. app.ServerConf.ProvisionerImagePullSecret,
  227. )
  228. if err != nil {
  229. app.handleErrorInternal(err, w)
  230. return
  231. }
  232. app.Logger.Info().Msgf("AWS ECR infra marked for destruction: %d", infra.ID)
  233. w.WriteHeader(http.StatusOK)
  234. }
  235. // HandleProvisionAWSEKSInfra provisions a new aws EKS instance for a project
  236. func (app *App) HandleProvisionAWSEKSInfra(w http.ResponseWriter, r *http.Request) {
  237. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  238. userID, err := app.getUserIDFromRequest(r)
  239. if err != nil || projID == 0 {
  240. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  241. return
  242. }
  243. form := &forms.CreateEKSInfra{
  244. ProjectID: uint(projID),
  245. }
  246. // decode from JSON to form value
  247. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  248. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  249. return
  250. }
  251. // validate the form
  252. if err := app.validator.Struct(form); err != nil {
  253. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  254. return
  255. }
  256. // convert the form to an aws infra instance
  257. infra, err := form.ToInfra()
  258. if err != nil {
  259. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  260. return
  261. }
  262. // handle write to the database
  263. infra, err = app.Repo.Infra.CreateInfra(infra)
  264. if err != nil {
  265. app.handleErrorDataWrite(err, w)
  266. return
  267. }
  268. awsInt, err := app.Repo.AWSIntegration.ReadAWSIntegration(infra.AWSIntegrationID)
  269. if err != nil {
  270. infra.Status = models.StatusError
  271. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  272. app.handleErrorDataRead(err, w)
  273. return
  274. }
  275. // launch provisioning pod
  276. _, err = app.ProvisionerAgent.ProvisionEKS(
  277. uint(projID),
  278. awsInt,
  279. form.EKSName,
  280. form.MachineType,
  281. *app.Repo,
  282. infra,
  283. provisioner.Apply,
  284. &app.DBConf,
  285. app.RedisConf,
  286. app.ServerConf.ProvisionerImageTag,
  287. app.ServerConf.ProvisionerImagePullSecret,
  288. )
  289. if err != nil {
  290. infra.Status = models.StatusError
  291. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  292. app.handleErrorInternal(err, w)
  293. return
  294. }
  295. app.Logger.Info().Msgf("New aws eks infra created: %d", infra.ID)
  296. app.analyticsClient.Track(analytics.ClusterProvisioningStartTrack(
  297. &analytics.ClusterProvisioningStartTrackOpts{
  298. ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(userID, uint(projID)),
  299. ClusterType: "EKS",
  300. },
  301. ))
  302. w.WriteHeader(http.StatusCreated)
  303. infraExt := infra.Externalize()
  304. if err := json.NewEncoder(w).Encode(infraExt); err != nil {
  305. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  306. return
  307. }
  308. }
  309. // HandleDestroyAWSEKSInfra destroys eks infra
  310. func (app *App) HandleDestroyAWSEKSInfra(w http.ResponseWriter, r *http.Request) {
  311. // get path parameters
  312. infraID, err := strconv.ParseUint(chi.URLParam(r, "infra_id"), 10, 64)
  313. // userID, err := app.getUserIDFromRequest(r)
  314. if err != nil {
  315. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  316. return
  317. }
  318. // read infra to get id
  319. infra, err := app.Repo.Infra.ReadInfra(uint(infraID))
  320. if err != nil {
  321. app.handleErrorDataRead(err, w)
  322. return
  323. }
  324. awsInt, err := app.Repo.AWSIntegration.ReadAWSIntegration(infra.AWSIntegrationID)
  325. form := &forms.DestroyEKSInfra{}
  326. // decode from JSON to form value
  327. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  328. infra.Status = models.StatusError
  329. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  330. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  331. return
  332. }
  333. // validate the form
  334. if err := app.validator.Struct(form); err != nil {
  335. infra.Status = models.StatusError
  336. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  337. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  338. return
  339. }
  340. // launch provisioning destruction pod
  341. // mark infra for deletion
  342. infra.Status = models.StatusDestroying
  343. infra, err = app.Repo.Infra.UpdateInfra(infra)
  344. if err != nil {
  345. app.handleErrorDataWrite(err, w)
  346. return
  347. }
  348. _, err = app.ProvisionerAgent.ProvisionEKS(
  349. infra.ProjectID,
  350. awsInt,
  351. form.EKSName,
  352. "",
  353. *app.Repo,
  354. infra,
  355. provisioner.Destroy,
  356. &app.DBConf,
  357. app.RedisConf,
  358. app.ServerConf.ProvisionerImageTag,
  359. app.ServerConf.ProvisionerImagePullSecret,
  360. )
  361. if err != nil {
  362. app.handleErrorInternal(err, w)
  363. return
  364. }
  365. app.Logger.Info().Msgf("AWS EKS infra marked for destruction: %d", infra.ID)
  366. w.WriteHeader(http.StatusOK)
  367. }
  368. // HandleProvisionGCPGCRInfra enables GCR for a project
  369. func (app *App) HandleProvisionGCPGCRInfra(w http.ResponseWriter, r *http.Request) {
  370. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  371. if err != nil || projID == 0 {
  372. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  373. return
  374. }
  375. form := &forms.CreateGCRInfra{
  376. ProjectID: uint(projID),
  377. }
  378. // decode from JSON to form value
  379. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  380. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  381. return
  382. }
  383. // validate the form
  384. if err := app.validator.Struct(form); err != nil {
  385. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  386. return
  387. }
  388. // convert the form to an aws infra instance
  389. infra, err := form.ToInfra()
  390. if err != nil {
  391. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  392. return
  393. }
  394. // handle write to the database
  395. infra, err = app.Repo.Infra.CreateInfra(infra)
  396. if err != nil {
  397. app.handleErrorDataWrite(err, w)
  398. return
  399. }
  400. gcpInt, err := app.Repo.GCPIntegration.ReadGCPIntegration(infra.GCPIntegrationID)
  401. if err != nil {
  402. infra.Status = models.StatusError
  403. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  404. app.handleErrorDataRead(err, w)
  405. return
  406. }
  407. // launch provisioning pod
  408. _, err = app.ProvisionerAgent.ProvisionGCR(
  409. uint(projID),
  410. gcpInt,
  411. *app.Repo,
  412. infra,
  413. provisioner.Apply,
  414. &app.DBConf,
  415. app.RedisConf,
  416. app.ServerConf.ProvisionerImageTag,
  417. app.ServerConf.ProvisionerImagePullSecret,
  418. )
  419. if err != nil {
  420. infra.Status = models.StatusError
  421. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  422. app.handleErrorInternal(err, w)
  423. return
  424. }
  425. app.Logger.Info().Msgf("New gcp gcr infra created: %d", infra.ID)
  426. w.WriteHeader(http.StatusCreated)
  427. infraExt := infra.Externalize()
  428. if err := json.NewEncoder(w).Encode(infraExt); err != nil {
  429. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  430. return
  431. }
  432. }
  433. // HandleProvisionGCPGKEInfra provisions a new GKE instance for a project
  434. func (app *App) HandleProvisionGCPGKEInfra(w http.ResponseWriter, r *http.Request) {
  435. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  436. userID, err := app.getUserIDFromRequest(r)
  437. if err != nil || projID == 0 {
  438. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  439. return
  440. }
  441. form := &forms.CreateGKEInfra{
  442. ProjectID: uint(projID),
  443. }
  444. // decode from JSON to form value
  445. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  446. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  447. return
  448. }
  449. // validate the form
  450. if err := app.validator.Struct(form); err != nil {
  451. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  452. return
  453. }
  454. // convert the form to an aws infra instance
  455. infra, err := form.ToInfra()
  456. if err != nil {
  457. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  458. return
  459. }
  460. // handle write to the database
  461. infra, err = app.Repo.Infra.CreateInfra(infra)
  462. if err != nil {
  463. app.handleErrorDataWrite(err, w)
  464. return
  465. }
  466. gcpInt, err := app.Repo.GCPIntegration.ReadGCPIntegration(infra.GCPIntegrationID)
  467. if err != nil {
  468. infra.Status = models.StatusError
  469. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  470. app.handleErrorDataRead(err, w)
  471. return
  472. }
  473. // launch provisioning pod
  474. _, err = app.ProvisionerAgent.ProvisionGKE(
  475. uint(projID),
  476. gcpInt,
  477. form.GKEName,
  478. *app.Repo,
  479. infra,
  480. provisioner.Apply,
  481. &app.DBConf,
  482. app.RedisConf,
  483. app.ServerConf.ProvisionerImageTag,
  484. app.ServerConf.ProvisionerImagePullSecret,
  485. )
  486. if err != nil {
  487. infra.Status = models.StatusError
  488. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  489. app.handleErrorInternal(err, w)
  490. return
  491. }
  492. app.Logger.Info().Msgf("New gcp gke infra created: %d", infra.ID)
  493. app.analyticsClient.Track(analytics.ClusterProvisioningStartTrack(
  494. &analytics.ClusterProvisioningStartTrackOpts{
  495. ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(userID, uint(projID)),
  496. ClusterType: "GKE",
  497. },
  498. ))
  499. w.WriteHeader(http.StatusCreated)
  500. infraExt := infra.Externalize()
  501. if err := json.NewEncoder(w).Encode(infraExt); err != nil {
  502. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  503. return
  504. }
  505. }
  506. // HandleDestroyGCPGKEInfra destroys gke infra
  507. func (app *App) HandleDestroyGCPGKEInfra(w http.ResponseWriter, r *http.Request) {
  508. // get path parameters
  509. infraID, err := strconv.ParseUint(chi.URLParam(r, "infra_id"), 10, 64)
  510. // userID, err := app.getUserIDFromRequest(r)
  511. if err != nil {
  512. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  513. return
  514. }
  515. // read infra to get id
  516. infra, err := app.Repo.Infra.ReadInfra(uint(infraID))
  517. if err != nil {
  518. app.handleErrorDataRead(err, w)
  519. return
  520. }
  521. gcpInt, err := app.Repo.GCPIntegration.ReadGCPIntegration(infra.GCPIntegrationID)
  522. form := &forms.DestroyGKEInfra{}
  523. // decode from JSON to form value
  524. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  525. infra.Status = models.StatusError
  526. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  527. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  528. return
  529. }
  530. // validate the form
  531. if err := app.validator.Struct(form); err != nil {
  532. infra.Status = models.StatusError
  533. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  534. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  535. return
  536. }
  537. // launch provisioning destruction pod
  538. // mark infra for deletion
  539. infra.Status = models.StatusDestroying
  540. infra, err = app.Repo.Infra.UpdateInfra(infra)
  541. if err != nil {
  542. app.handleErrorDataWrite(err, w)
  543. return
  544. }
  545. _, err = app.ProvisionerAgent.ProvisionGKE(
  546. infra.ProjectID,
  547. gcpInt,
  548. form.GKEName,
  549. *app.Repo,
  550. infra,
  551. provisioner.Destroy,
  552. &app.DBConf,
  553. app.RedisConf,
  554. app.ServerConf.ProvisionerImageTag,
  555. app.ServerConf.ProvisionerImagePullSecret,
  556. )
  557. if err != nil {
  558. app.handleErrorInternal(err, w)
  559. return
  560. }
  561. app.Logger.Info().Msgf("GCP GKE infra marked for destruction: %d", infra.ID)
  562. w.WriteHeader(http.StatusOK)
  563. }
  564. // HandleGetProvisioningLogs returns real-time logs of the provisioning process via websockets
  565. func (app *App) HandleGetProvisioningLogs(w http.ResponseWriter, r *http.Request) {
  566. // get path parameters
  567. infraID, err := strconv.ParseUint(chi.URLParam(r, "infra_id"), 10, 64)
  568. if err != nil {
  569. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  570. return
  571. }
  572. // read infra to get id
  573. infra, err := app.Repo.Infra.ReadInfra(uint(infraID))
  574. if err != nil {
  575. app.handleErrorDataRead(err, w)
  576. return
  577. }
  578. streamName := infra.GetUniqueName()
  579. upgrader.CheckOrigin = func(r *http.Request) bool { return true }
  580. // upgrade to websocket.
  581. conn, err := upgrader.Upgrade(w, r, nil)
  582. if err != nil {
  583. app.handleErrorUpgradeWebsocket(err, w)
  584. }
  585. client, err := adapter.NewRedisClient(app.RedisConf)
  586. if err != nil {
  587. app.handleErrorInternal(err, w)
  588. return
  589. }
  590. err = provisioner.ResourceStream(client, streamName, conn)
  591. if err != nil {
  592. app.handleErrorWebsocketWrite(err, w)
  593. return
  594. }
  595. }
  596. // HandleProvisionDODOCRInfra provisions a new digitalocean DOCR instance for a project
  597. func (app *App) HandleProvisionDODOCRInfra(w http.ResponseWriter, r *http.Request) {
  598. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  599. if err != nil || projID == 0 {
  600. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  601. return
  602. }
  603. form := &forms.CreateDOCRInfra{
  604. ProjectID: uint(projID),
  605. }
  606. // decode from JSON to form value
  607. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  608. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  609. return
  610. }
  611. // validate the form
  612. if err := app.validator.Struct(form); err != nil {
  613. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  614. return
  615. }
  616. // convert the form to an aws infra instance
  617. infra, err := form.ToInfra()
  618. if err != nil {
  619. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  620. return
  621. }
  622. // handle write to the database
  623. infra, err = app.Repo.Infra.CreateInfra(infra)
  624. if err != nil {
  625. app.handleErrorDataWrite(err, w)
  626. return
  627. }
  628. oauthInt, err := app.Repo.OAuthIntegration.ReadOAuthIntegration(infra.DOIntegrationID)
  629. if err != nil {
  630. infra.Status = models.StatusError
  631. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  632. app.handleErrorDataRead(err, w)
  633. return
  634. }
  635. // launch provisioning pod
  636. _, err = app.ProvisionerAgent.ProvisionDOCR(
  637. uint(projID),
  638. oauthInt,
  639. app.DOConf,
  640. *app.Repo,
  641. form.DOCRName,
  642. form.DOCRSubscriptionTier,
  643. infra,
  644. provisioner.Apply,
  645. &app.DBConf,
  646. app.RedisConf,
  647. app.ServerConf.ProvisionerImageTag,
  648. app.ServerConf.ProvisionerImagePullSecret,
  649. )
  650. if err != nil {
  651. infra.Status = models.StatusError
  652. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  653. app.handleErrorInternal(err, w)
  654. return
  655. }
  656. app.Logger.Info().Msgf("New do docr infra created: %d", infra.ID)
  657. w.WriteHeader(http.StatusCreated)
  658. infraExt := infra.Externalize()
  659. if err := json.NewEncoder(w).Encode(infraExt); err != nil {
  660. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  661. return
  662. }
  663. }
  664. // HandleDestroyAWSDOCRInfra destroys docr infra
  665. func (app *App) HandleDestroyDODOCRInfra(w http.ResponseWriter, r *http.Request) {
  666. // get path parameters
  667. infraID, err := strconv.ParseUint(chi.URLParam(r, "infra_id"), 10, 64)
  668. if err != nil {
  669. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  670. return
  671. }
  672. // read infra to get id
  673. infra, err := app.Repo.Infra.ReadInfra(uint(infraID))
  674. if err != nil {
  675. app.handleErrorDataRead(err, w)
  676. return
  677. }
  678. oauthInt, err := app.Repo.OAuthIntegration.ReadOAuthIntegration(infra.DOIntegrationID)
  679. form := &forms.DestroyDOCRInfra{}
  680. // decode from JSON to form value
  681. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  682. infra.Status = models.StatusError
  683. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  684. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  685. return
  686. }
  687. // validate the form
  688. if err := app.validator.Struct(form); err != nil {
  689. infra.Status = models.StatusError
  690. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  691. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  692. return
  693. }
  694. // launch provisioning destruction pod
  695. // mark infra for deletion
  696. infra.Status = models.StatusDestroying
  697. infra, err = app.Repo.Infra.UpdateInfra(infra)
  698. if err != nil {
  699. app.handleErrorDataWrite(err, w)
  700. return
  701. }
  702. _, err = app.ProvisionerAgent.ProvisionDOCR(
  703. infra.ProjectID,
  704. oauthInt,
  705. app.DOConf,
  706. *app.Repo,
  707. form.DOCRName,
  708. "basic", // this doesn't matter for destroy
  709. infra,
  710. provisioner.Destroy,
  711. &app.DBConf,
  712. app.RedisConf,
  713. app.ServerConf.ProvisionerImageTag,
  714. app.ServerConf.ProvisionerImagePullSecret,
  715. )
  716. if err != nil {
  717. app.handleErrorInternal(err, w)
  718. return
  719. }
  720. app.Logger.Info().Msgf("DO DOCR infra marked for destruction: %d", infra.ID)
  721. w.WriteHeader(http.StatusOK)
  722. }
  723. // HandleProvisionDODOKSInfra provisions a new DO DOKS instance for a project
  724. func (app *App) HandleProvisionDODOKSInfra(w http.ResponseWriter, r *http.Request) {
  725. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  726. userID, err := app.getUserIDFromRequest(r)
  727. if err != nil || projID == 0 {
  728. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  729. return
  730. }
  731. form := &forms.CreateDOKSInfra{
  732. ProjectID: uint(projID),
  733. }
  734. // decode from JSON to form value
  735. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  736. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  737. return
  738. }
  739. // validate the form
  740. if err := app.validator.Struct(form); err != nil {
  741. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  742. return
  743. }
  744. // convert the form to an aws infra instance
  745. infra, err := form.ToInfra()
  746. if err != nil {
  747. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  748. return
  749. }
  750. // handle write to the database
  751. infra, err = app.Repo.Infra.CreateInfra(infra)
  752. if err != nil {
  753. app.handleErrorDataWrite(err, w)
  754. return
  755. }
  756. oauthInt, err := app.Repo.OAuthIntegration.ReadOAuthIntegration(infra.DOIntegrationID)
  757. if err != nil {
  758. infra.Status = models.StatusError
  759. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  760. app.handleErrorDataRead(err, w)
  761. return
  762. }
  763. // launch provisioning pod
  764. _, err = app.ProvisionerAgent.ProvisionDOKS(
  765. uint(projID),
  766. oauthInt,
  767. app.DOConf,
  768. *app.Repo,
  769. form.DORegion,
  770. form.DOKSName,
  771. infra,
  772. provisioner.Apply,
  773. &app.DBConf,
  774. app.RedisConf,
  775. app.ServerConf.ProvisionerImageTag,
  776. app.ServerConf.ProvisionerImagePullSecret,
  777. )
  778. if err != nil {
  779. infra.Status = models.StatusError
  780. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  781. app.handleErrorInternal(err, w)
  782. return
  783. }
  784. app.Logger.Info().Msgf("New do doks infra created: %d", infra.ID)
  785. app.analyticsClient.Track(analytics.ClusterProvisioningStartTrack(
  786. &analytics.ClusterProvisioningStartTrackOpts{
  787. ProjectScopedTrackOpts: analytics.GetProjectScopedTrackOpts(userID, uint(projID)),
  788. ClusterType: "DOKS",
  789. },
  790. ))
  791. w.WriteHeader(http.StatusCreated)
  792. infraExt := infra.Externalize()
  793. if err := json.NewEncoder(w).Encode(infraExt); err != nil {
  794. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  795. return
  796. }
  797. }
  798. // HandleDestroyDODOKSInfra destroys DOKS infra
  799. func (app *App) HandleDestroyDODOKSInfra(w http.ResponseWriter, r *http.Request) {
  800. // get path parameters
  801. infraID, err := strconv.ParseUint(chi.URLParam(r, "infra_id"), 10, 64)
  802. if err != nil {
  803. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  804. return
  805. }
  806. // read infra to get id
  807. infra, err := app.Repo.Infra.ReadInfra(uint(infraID))
  808. if err != nil {
  809. app.handleErrorDataRead(err, w)
  810. return
  811. }
  812. oauthInt, err := app.Repo.OAuthIntegration.ReadOAuthIntegration(infra.DOIntegrationID)
  813. form := &forms.DestroyDOKSInfra{}
  814. // decode from JSON to form value
  815. if err := json.NewDecoder(r.Body).Decode(form); err != nil {
  816. infra.Status = models.StatusError
  817. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  818. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  819. return
  820. }
  821. // validate the form
  822. if err := app.validator.Struct(form); err != nil {
  823. infra.Status = models.StatusError
  824. infra, _ = app.Repo.Infra.UpdateInfra(infra)
  825. app.handleErrorFormValidation(err, ErrProjectValidateFields, w)
  826. return
  827. }
  828. // launch provisioning destruction pod
  829. // mark infra for deletion
  830. infra.Status = models.StatusDestroying
  831. infra, err = app.Repo.Infra.UpdateInfra(infra)
  832. if err != nil {
  833. app.handleErrorDataWrite(err, w)
  834. return
  835. }
  836. _, err = app.ProvisionerAgent.ProvisionDOKS(
  837. infra.ProjectID,
  838. oauthInt,
  839. app.DOConf,
  840. *app.Repo,
  841. "nyc1",
  842. form.DOKSName,
  843. infra,
  844. provisioner.Destroy,
  845. &app.DBConf,
  846. app.RedisConf,
  847. app.ServerConf.ProvisionerImageTag,
  848. app.ServerConf.ProvisionerImagePullSecret,
  849. )
  850. if err != nil {
  851. app.handleErrorInternal(err, w)
  852. return
  853. }
  854. app.Logger.Info().Msgf("DO DOKS infra marked for destruction: %d", infra.ID)
  855. w.WriteHeader(http.StatusOK)
  856. }