2
0

provision_handler.go 23 KB

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