provision_handler.go 24 KB

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