k8s_handler.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. package api
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "net/url"
  7. "github.com/go-chi/chi"
  8. "github.com/gorilla/schema"
  9. "github.com/gorilla/websocket"
  10. "github.com/porter-dev/porter/internal/forms"
  11. "github.com/porter-dev/porter/internal/kubernetes"
  12. "github.com/porter-dev/porter/internal/kubernetes/prometheus"
  13. v1 "k8s.io/api/core/v1"
  14. )
  15. // Enumeration of k8s API error codes, represented as int64
  16. const (
  17. ErrK8sDecode ErrorCode = iota + 600
  18. ErrK8sValidate
  19. ErrEnvDecode
  20. )
  21. var upgrader = websocket.Upgrader{
  22. ReadBufferSize: 1024,
  23. WriteBufferSize: 1024,
  24. }
  25. // HandleListNamespaces retrieves a list of namespaces
  26. func (app *App) HandleListNamespaces(w http.ResponseWriter, r *http.Request) {
  27. vals, err := url.ParseQuery(r.URL.RawQuery)
  28. if err != nil {
  29. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  30. return
  31. }
  32. // get the filter options
  33. form := &forms.K8sForm{
  34. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  35. Repo: app.Repo,
  36. DigitalOceanOAuth: app.DOConf,
  37. },
  38. }
  39. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  40. // validate the form
  41. if err := app.validator.Struct(form); err != nil {
  42. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  43. return
  44. }
  45. // create a new agent
  46. var agent *kubernetes.Agent
  47. if app.ServerConf.IsTesting {
  48. agent = app.TestAgents.K8sAgent
  49. } else {
  50. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  51. }
  52. namespaces, err := agent.ListNamespaces()
  53. if err != nil {
  54. app.handleErrorDataRead(err, w)
  55. return
  56. }
  57. if err := json.NewEncoder(w).Encode(namespaces); err != nil {
  58. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  59. return
  60. }
  61. }
  62. // HandleCreateConfigMap deletes the pod given the name and namespace.
  63. func (app *App) HandleCreateConfigMap(w http.ResponseWriter, r *http.Request) {
  64. fmt.Println("CREATING CONFGIMAP")
  65. vals, err := url.ParseQuery(r.URL.RawQuery)
  66. if err != nil {
  67. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  68. return
  69. }
  70. // get the filter options
  71. form := &forms.K8sForm{
  72. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  73. Repo: app.Repo,
  74. DigitalOceanOAuth: app.DOConf,
  75. },
  76. }
  77. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  78. // validate the form
  79. if err := app.validator.Struct(form); err != nil {
  80. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  81. return
  82. }
  83. // create a new agent
  84. var agent *kubernetes.Agent
  85. if app.ServerConf.IsTesting {
  86. agent = app.TestAgents.K8sAgent
  87. } else {
  88. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  89. }
  90. configMap := &forms.ConfigMapForm{}
  91. if err := json.NewDecoder(r.Body).Decode(configMap); err != nil {
  92. app.handleErrorFormDecoding(err, ErrUserDecode, w)
  93. return
  94. }
  95. _, err = agent.CreateConfigMap(configMap.Name, configMap.Namespace, configMap.EnvVariables)
  96. if err != nil {
  97. app.handleErrorInternal(err, w)
  98. return
  99. }
  100. if err := json.NewEncoder(w).Encode(configMap); err != nil {
  101. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  102. return
  103. }
  104. w.WriteHeader(http.StatusOK)
  105. return
  106. }
  107. // HandleListConfigMaps lists all configmaps in a namespace.
  108. func (app *App) HandleListConfigMaps(w http.ResponseWriter, r *http.Request) {
  109. vals, err := url.ParseQuery(r.URL.RawQuery)
  110. if err != nil {
  111. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  112. return
  113. }
  114. // get the filter options
  115. form := &forms.K8sForm{
  116. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  117. Repo: app.Repo,
  118. DigitalOceanOAuth: app.DOConf,
  119. },
  120. }
  121. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  122. // validate the form
  123. if err := app.validator.Struct(form); err != nil {
  124. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  125. return
  126. }
  127. // create a new agent
  128. var agent *kubernetes.Agent
  129. if app.ServerConf.IsTesting {
  130. agent = app.TestAgents.K8sAgent
  131. } else {
  132. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  133. }
  134. configMaps, err := agent.ListConfigMaps(vals["namespace"][0])
  135. if err != nil {
  136. app.handleErrorInternal(err, w)
  137. return
  138. }
  139. if err := json.NewEncoder(w).Encode(configMaps); err != nil {
  140. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  141. return
  142. }
  143. w.WriteHeader(http.StatusOK)
  144. return
  145. }
  146. // HandleGetConfigMap retreives the configmap given the name and namespace.
  147. func (app *App) HandleGetConfigMap(w http.ResponseWriter, r *http.Request) {
  148. vals, err := url.ParseQuery(r.URL.RawQuery)
  149. if err != nil {
  150. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  151. return
  152. }
  153. // get the filter options
  154. form := &forms.K8sForm{
  155. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  156. Repo: app.Repo,
  157. DigitalOceanOAuth: app.DOConf,
  158. },
  159. }
  160. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  161. // validate the form
  162. if err := app.validator.Struct(form); err != nil {
  163. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  164. return
  165. }
  166. // create a new agent
  167. var agent *kubernetes.Agent
  168. if app.ServerConf.IsTesting {
  169. agent = app.TestAgents.K8sAgent
  170. } else {
  171. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  172. }
  173. configMap, err := agent.GetConfigMap(vals["name"][0], vals["namespace"][0])
  174. if err != nil {
  175. app.handleErrorInternal(err, w)
  176. return
  177. }
  178. if err := json.NewEncoder(w).Encode(configMap); err != nil {
  179. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  180. return
  181. }
  182. w.WriteHeader(http.StatusOK)
  183. return
  184. }
  185. // HandleDeleteConfigMap deletes the pod given the name and namespace.
  186. func (app *App) HandleDeleteConfigMap(w http.ResponseWriter, r *http.Request) {
  187. vals, err := url.ParseQuery(r.URL.RawQuery)
  188. if err != nil {
  189. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  190. return
  191. }
  192. // get the filter options
  193. form := &forms.K8sForm{
  194. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  195. Repo: app.Repo,
  196. DigitalOceanOAuth: app.DOConf,
  197. },
  198. }
  199. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  200. // validate the form
  201. if err := app.validator.Struct(form); err != nil {
  202. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  203. return
  204. }
  205. // create a new agent
  206. var agent *kubernetes.Agent
  207. if app.ServerConf.IsTesting {
  208. agent = app.TestAgents.K8sAgent
  209. } else {
  210. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  211. }
  212. err = agent.DeleteConfigMap(vals["name"][0], vals["namespace"][0])
  213. if err != nil {
  214. app.handleErrorInternal(err, w)
  215. return
  216. }
  217. w.WriteHeader(http.StatusOK)
  218. return
  219. }
  220. // HandleUpdateConfigMap deletes the pod given the name and namespace.
  221. func (app *App) HandleUpdateConfigMap(w http.ResponseWriter, r *http.Request) {
  222. vals, err := url.ParseQuery(r.URL.RawQuery)
  223. if err != nil {
  224. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  225. return
  226. }
  227. // get the filter options
  228. form := &forms.K8sForm{
  229. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  230. Repo: app.Repo,
  231. DigitalOceanOAuth: app.DOConf,
  232. },
  233. }
  234. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  235. // validate the form
  236. if err := app.validator.Struct(form); err != nil {
  237. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  238. return
  239. }
  240. // create a new agent
  241. var agent *kubernetes.Agent
  242. if app.ServerConf.IsTesting {
  243. agent = app.TestAgents.K8sAgent
  244. } else {
  245. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  246. }
  247. configMap := &forms.ConfigMapForm{}
  248. if err := json.NewDecoder(r.Body).Decode(configMap); err != nil {
  249. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  250. return
  251. }
  252. _, err = agent.UpdateConfigMap(configMap.Name, configMap.Namespace, configMap.EnvVariables)
  253. if err != nil {
  254. app.handleErrorInternal(err, w)
  255. return
  256. }
  257. if err := json.NewEncoder(w).Encode(configMap); err != nil {
  258. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  259. return
  260. }
  261. w.WriteHeader(http.StatusOK)
  262. return
  263. }
  264. // HandleGetPodLogs returns real-time logs of the pod via websockets
  265. // TODO: Refactor repeated calls.
  266. func (app *App) HandleGetPodLogs(w http.ResponseWriter, r *http.Request) {
  267. // get session to retrieve correct kubeconfig
  268. _, err := app.Store.Get(r, app.ServerConf.CookieName)
  269. // get path parameters
  270. namespace := chi.URLParam(r, "namespace")
  271. podName := chi.URLParam(r, "name")
  272. if err != nil {
  273. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  274. return
  275. }
  276. vals, err := url.ParseQuery(r.URL.RawQuery)
  277. if err != nil {
  278. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  279. return
  280. }
  281. // get the filter options
  282. form := &forms.K8sForm{
  283. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  284. Repo: app.Repo,
  285. DigitalOceanOAuth: app.DOConf,
  286. },
  287. }
  288. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  289. // validate the form
  290. if err := app.validator.Struct(form); err != nil {
  291. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  292. return
  293. }
  294. // create a new agent
  295. var agent *kubernetes.Agent
  296. if app.ServerConf.IsTesting {
  297. agent = app.TestAgents.K8sAgent
  298. } else {
  299. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  300. }
  301. upgrader.CheckOrigin = func(r *http.Request) bool { return true }
  302. // upgrade to websocket.
  303. conn, err := upgrader.Upgrade(w, r, nil)
  304. if err != nil {
  305. app.handleErrorUpgradeWebsocket(err, w)
  306. }
  307. err = agent.GetPodLogs(namespace, podName, conn)
  308. if err != nil {
  309. app.handleErrorWebsocketWrite(err, w)
  310. return
  311. }
  312. }
  313. // HandleDeletePod deletes the pod given the name and namespace.
  314. func (app *App) HandleDeletePod(w http.ResponseWriter, r *http.Request) {
  315. // get path parameters
  316. namespace := chi.URLParam(r, "namespace")
  317. name := chi.URLParam(r, "name")
  318. vals, err := url.ParseQuery(r.URL.RawQuery)
  319. if err != nil {
  320. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  321. return
  322. }
  323. // get the filter options
  324. form := &forms.K8sForm{
  325. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  326. Repo: app.Repo,
  327. DigitalOceanOAuth: app.DOConf,
  328. },
  329. }
  330. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  331. // validate the form
  332. if err := app.validator.Struct(form); err != nil {
  333. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  334. return
  335. }
  336. // create a new agent
  337. var agent *kubernetes.Agent
  338. if app.ServerConf.IsTesting {
  339. agent = app.TestAgents.K8sAgent
  340. } else {
  341. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  342. }
  343. err = agent.DeletePod(namespace, name)
  344. if err != nil {
  345. app.handleErrorInternal(err, w)
  346. return
  347. }
  348. w.WriteHeader(http.StatusOK)
  349. return
  350. }
  351. // HandleGetIngress returns the ingress object given the name and namespace.
  352. func (app *App) HandleGetIngress(w http.ResponseWriter, r *http.Request) {
  353. // get session to retrieve correct kubeconfig
  354. _, err := app.Store.Get(r, app.ServerConf.CookieName)
  355. // get path parameters
  356. namespace := chi.URLParam(r, "namespace")
  357. name := chi.URLParam(r, "name")
  358. if err != nil {
  359. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  360. return
  361. }
  362. vals, err := url.ParseQuery(r.URL.RawQuery)
  363. if err != nil {
  364. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  365. return
  366. }
  367. // get the filter options
  368. form := &forms.K8sForm{
  369. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  370. Repo: app.Repo,
  371. DigitalOceanOAuth: app.DOConf,
  372. },
  373. }
  374. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  375. // validate the form
  376. if err := app.validator.Struct(form); err != nil {
  377. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  378. return
  379. }
  380. // create a new agent
  381. var agent *kubernetes.Agent
  382. if app.ServerConf.IsTesting {
  383. agent = app.TestAgents.K8sAgent
  384. } else {
  385. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  386. }
  387. ingress, err := agent.GetIngress(namespace, name)
  388. if err != nil {
  389. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  390. return
  391. }
  392. if err := json.NewEncoder(w).Encode(ingress); err != nil {
  393. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  394. return
  395. }
  396. }
  397. // HandleListPods returns all pods that match the given selectors
  398. // TODO: Refactor repeated calls.
  399. func (app *App) HandleListPods(w http.ResponseWriter, r *http.Request) {
  400. // get session to retrieve correct kubeconfig
  401. _, err := app.Store.Get(r, app.ServerConf.CookieName)
  402. if err != nil {
  403. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  404. return
  405. }
  406. vals, err := url.ParseQuery(r.URL.RawQuery)
  407. if err != nil {
  408. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  409. return
  410. }
  411. // get the filter options
  412. form := &forms.K8sForm{
  413. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  414. Repo: app.Repo,
  415. DigitalOceanOAuth: app.DOConf,
  416. },
  417. }
  418. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  419. // validate the form
  420. if err := app.validator.Struct(form); err != nil {
  421. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  422. return
  423. }
  424. // create a new agent
  425. var agent *kubernetes.Agent
  426. if app.ServerConf.IsTesting {
  427. agent = app.TestAgents.K8sAgent
  428. } else {
  429. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  430. }
  431. pods := []v1.Pod{}
  432. for _, selector := range vals["selectors"] {
  433. podsList, err := agent.GetPodsByLabel(selector)
  434. if err != nil {
  435. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  436. return
  437. }
  438. for _, pod := range podsList.Items {
  439. pods = append(pods, pod)
  440. }
  441. }
  442. if err := json.NewEncoder(w).Encode(pods); err != nil {
  443. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  444. return
  445. }
  446. }
  447. // HandleListJobsByChart lists all jobs belonging to a specific Helm chart
  448. func (app *App) HandleListJobsByChart(w http.ResponseWriter, r *http.Request) {
  449. // get path parameters
  450. namespace := chi.URLParam(r, "namespace")
  451. chart := chi.URLParam(r, "chart")
  452. releaseName := chi.URLParam(r, "release_name")
  453. vals, err := url.ParseQuery(r.URL.RawQuery)
  454. if err != nil {
  455. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  456. return
  457. }
  458. // get the filter options
  459. form := &forms.K8sForm{
  460. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  461. Repo: app.Repo,
  462. DigitalOceanOAuth: app.DOConf,
  463. },
  464. }
  465. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  466. // validate the form
  467. if err := app.validator.Struct(form); err != nil {
  468. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  469. return
  470. }
  471. // create a new agent
  472. var agent *kubernetes.Agent
  473. if app.ServerConf.IsTesting {
  474. agent = app.TestAgents.K8sAgent
  475. } else {
  476. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  477. }
  478. jobs, err := agent.ListJobsByLabel(namespace, kubernetes.Label{
  479. Key: "helm.sh/chart",
  480. Val: chart,
  481. }, kubernetes.Label{
  482. Key: "meta.helm.sh/release-name",
  483. Val: releaseName,
  484. })
  485. if err != nil {
  486. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  487. return
  488. }
  489. if err := json.NewEncoder(w).Encode(jobs); err != nil {
  490. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  491. return
  492. }
  493. }
  494. // HandleListJobPods lists all pods belonging to a specific job
  495. func (app *App) HandleListJobPods(w http.ResponseWriter, r *http.Request) {
  496. // get path parameters
  497. namespace := chi.URLParam(r, "namespace")
  498. name := chi.URLParam(r, "name")
  499. vals, err := url.ParseQuery(r.URL.RawQuery)
  500. if err != nil {
  501. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  502. return
  503. }
  504. // get the filter options
  505. form := &forms.K8sForm{
  506. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  507. Repo: app.Repo,
  508. DigitalOceanOAuth: app.DOConf,
  509. },
  510. }
  511. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  512. // validate the form
  513. if err := app.validator.Struct(form); err != nil {
  514. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  515. return
  516. }
  517. // create a new agent
  518. var agent *kubernetes.Agent
  519. if app.ServerConf.IsTesting {
  520. agent = app.TestAgents.K8sAgent
  521. } else {
  522. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  523. }
  524. pods, err := agent.GetJobPods(namespace, name)
  525. if err != nil {
  526. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  527. return
  528. }
  529. if err := json.NewEncoder(w).Encode(pods); err != nil {
  530. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  531. return
  532. }
  533. }
  534. // HandleStreamControllerStatus test calls
  535. // TODO: Refactor repeated calls.
  536. func (app *App) HandleStreamControllerStatus(w http.ResponseWriter, r *http.Request) {
  537. // get session to retrieve correct kubeconfig
  538. _, err := app.Store.Get(r, app.ServerConf.CookieName)
  539. if err != nil {
  540. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  541. return
  542. }
  543. vals, err := url.ParseQuery(r.URL.RawQuery)
  544. if err != nil {
  545. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  546. return
  547. }
  548. // get the filter options
  549. form := &forms.K8sForm{
  550. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  551. Repo: app.Repo,
  552. DigitalOceanOAuth: app.DOConf,
  553. },
  554. }
  555. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  556. // validate the form
  557. if err := app.validator.Struct(form); err != nil {
  558. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  559. return
  560. }
  561. // create a new agent
  562. var agent *kubernetes.Agent
  563. if app.ServerConf.IsTesting {
  564. agent = app.TestAgents.K8sAgent
  565. } else {
  566. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  567. }
  568. upgrader.CheckOrigin = func(r *http.Request) bool { return true }
  569. // upgrade to websocket.
  570. conn, err := upgrader.Upgrade(w, r, nil)
  571. if err != nil {
  572. app.handleErrorUpgradeWebsocket(err, w)
  573. }
  574. // get path parameters
  575. kind := chi.URLParam(r, "kind")
  576. err = agent.StreamControllerStatus(conn, kind)
  577. if err != nil {
  578. app.handleErrorWebsocketWrite(err, w)
  579. return
  580. }
  581. }
  582. // HandleDetectPrometheusInstalled detects a prometheus installation in the target cluster
  583. func (app *App) HandleDetectPrometheusInstalled(w http.ResponseWriter, r *http.Request) {
  584. vals, err := url.ParseQuery(r.URL.RawQuery)
  585. if err != nil {
  586. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  587. return
  588. }
  589. // get the filter options
  590. form := &forms.K8sForm{
  591. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  592. Repo: app.Repo,
  593. DigitalOceanOAuth: app.DOConf,
  594. },
  595. }
  596. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  597. // validate the form
  598. if err := app.validator.Struct(form); err != nil {
  599. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  600. return
  601. }
  602. // create a new agent
  603. var agent *kubernetes.Agent
  604. if app.ServerConf.IsTesting {
  605. agent = app.TestAgents.K8sAgent
  606. } else {
  607. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  608. }
  609. // detect prometheus service
  610. _, found, err := prometheus.GetPrometheusService(agent.Clientset)
  611. if !found {
  612. http.NotFound(w, r)
  613. return
  614. }
  615. w.WriteHeader(http.StatusOK)
  616. return
  617. }
  618. // HandleListNGINXIngresses lists all NGINX ingresses in a target cluster
  619. func (app *App) HandleListNGINXIngresses(w http.ResponseWriter, r *http.Request) {
  620. vals, err := url.ParseQuery(r.URL.RawQuery)
  621. if err != nil {
  622. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  623. return
  624. }
  625. // get the filter options
  626. form := &forms.K8sForm{
  627. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  628. Repo: app.Repo,
  629. DigitalOceanOAuth: app.DOConf,
  630. },
  631. }
  632. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  633. // validate the form
  634. if err := app.validator.Struct(form); err != nil {
  635. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  636. return
  637. }
  638. // create a new agent
  639. var agent *kubernetes.Agent
  640. if app.ServerConf.IsTesting {
  641. agent = app.TestAgents.K8sAgent
  642. } else {
  643. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  644. }
  645. res, err := prometheus.GetIngressesWithNGINXAnnotation(agent.Clientset)
  646. if err != nil {
  647. app.handleErrorInternal(err, w)
  648. return
  649. }
  650. w.WriteHeader(http.StatusOK)
  651. if err := json.NewEncoder(w).Encode(res); err != nil {
  652. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  653. return
  654. }
  655. }
  656. func (app *App) HandleGetPodMetrics(w http.ResponseWriter, r *http.Request) {
  657. vals, err := url.ParseQuery(r.URL.RawQuery)
  658. if err != nil {
  659. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  660. return
  661. }
  662. // get the filter options
  663. form := &forms.MetricsQueryForm{
  664. K8sForm: &forms.K8sForm{
  665. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  666. Repo: app.Repo,
  667. DigitalOceanOAuth: app.DOConf,
  668. },
  669. },
  670. QueryOpts: &prometheus.QueryOpts{},
  671. }
  672. form.K8sForm.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  673. // decode from JSON to form value
  674. decoder := schema.NewDecoder()
  675. decoder.IgnoreUnknownKeys(true)
  676. if err := decoder.Decode(form.QueryOpts, vals); err != nil {
  677. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  678. return
  679. }
  680. // validate the form
  681. if err := app.validator.Struct(form); err != nil {
  682. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  683. return
  684. }
  685. // create a new agent
  686. var agent *kubernetes.Agent
  687. if app.ServerConf.IsTesting {
  688. agent = app.TestAgents.K8sAgent
  689. } else {
  690. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  691. }
  692. // get prometheus service
  693. promSvc, found, err := prometheus.GetPrometheusService(agent.Clientset)
  694. if err != nil {
  695. app.handleErrorInternal(err, w)
  696. return
  697. }
  698. if !found {
  699. app.handleErrorInternal(err, w)
  700. return
  701. }
  702. rawQuery, err := prometheus.QueryPrometheus(agent.Clientset, promSvc, form.QueryOpts)
  703. if err != nil {
  704. app.handleErrorInternal(err, w)
  705. return
  706. }
  707. fmt.Fprint(w, string(rawQuery))
  708. }