provision_handler.go 25 KB

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