k8s_handler.go 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546
  1. package api
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "github.com/go-chi/chi"
  7. "github.com/gorilla/schema"
  8. "github.com/gorilla/websocket"
  9. "github.com/porter-dev/porter/internal/forms"
  10. "github.com/porter-dev/porter/internal/kubernetes"
  11. "github.com/porter-dev/porter/internal/kubernetes/nodes"
  12. "github.com/porter-dev/porter/internal/kubernetes/prometheus"
  13. v1 "k8s.io/api/core/v1"
  14. "k8s.io/client-go/tools/clientcmd"
  15. "net/http"
  16. "net/url"
  17. "strconv"
  18. "time"
  19. )
  20. // Enumeration of k8s API error codes, represented as int64
  21. const (
  22. ErrK8sDecode ErrorCode = iota + 600
  23. ErrK8sValidate
  24. ErrEnvDecode
  25. )
  26. var upgrader = websocket.Upgrader{
  27. ReadBufferSize: 1024,
  28. WriteBufferSize: 1024,
  29. }
  30. // HandleListNamespaces retrieves a list of namespaces
  31. func (app *App) HandleListNamespaces(w http.ResponseWriter, r *http.Request) {
  32. vals, err := url.ParseQuery(r.URL.RawQuery)
  33. if err != nil {
  34. http.Error(w, err.Error(), http.StatusInternalServerError)
  35. return
  36. }
  37. // get the filter options
  38. form := &forms.K8sForm{
  39. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  40. Repo: app.Repo,
  41. DigitalOceanOAuth: app.DOConf,
  42. },
  43. }
  44. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  45. // validate the form
  46. if err := app.validator.Struct(form); err != nil {
  47. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  48. return
  49. }
  50. // create a new agent
  51. var agent *kubernetes.Agent
  52. if app.ServerConf.IsTesting {
  53. agent = app.TestAgents.K8sAgent
  54. } else {
  55. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  56. }
  57. namespaces, err := agent.ListNamespaces()
  58. if err != nil {
  59. app.handleErrorDataRead(err, w)
  60. return
  61. }
  62. if err := json.NewEncoder(w).Encode(namespaces); err != nil {
  63. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  64. return
  65. }
  66. }
  67. // HandleCreateNamespace creates a new namespace given the name.
  68. func (app *App) HandleCreateNamespace(w http.ResponseWriter, r *http.Request) {
  69. vals, err := url.ParseQuery(r.URL.RawQuery)
  70. if err != nil {
  71. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  72. return
  73. }
  74. // get the filter options
  75. form := &forms.K8sForm{
  76. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  77. Repo: app.Repo,
  78. DigitalOceanOAuth: app.DOConf,
  79. },
  80. }
  81. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  82. // validate the form
  83. if err := app.validator.Struct(form); err != nil {
  84. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  85. return
  86. }
  87. // create a new agent
  88. var agent *kubernetes.Agent
  89. if app.ServerConf.IsTesting {
  90. agent = app.TestAgents.K8sAgent
  91. } else {
  92. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  93. }
  94. ns := &forms.NamespaceForm{}
  95. if err := json.NewDecoder(r.Body).Decode(ns); err != nil {
  96. app.handleErrorFormDecoding(err, ErrUserDecode, w)
  97. return
  98. }
  99. namespace, err := agent.CreateNamespace(ns.Name)
  100. if err != nil {
  101. app.handleErrorInternal(err, w)
  102. return
  103. }
  104. if err := json.NewEncoder(w).Encode(namespace); err != nil {
  105. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  106. return
  107. }
  108. w.WriteHeader(http.StatusOK)
  109. return
  110. }
  111. // HandleDeleteNamespace deletes a namespace given the name.
  112. func (app *App) HandleDeleteNamespace(w http.ResponseWriter, r *http.Request) {
  113. vals, err := url.ParseQuery(r.URL.RawQuery)
  114. if err != nil {
  115. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  116. return
  117. }
  118. // get the filter options
  119. form := &forms.K8sForm{
  120. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  121. Repo: app.Repo,
  122. DigitalOceanOAuth: app.DOConf,
  123. },
  124. }
  125. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  126. // validate the form
  127. if err := app.validator.Struct(form); err != nil {
  128. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  129. return
  130. }
  131. // create a new agent
  132. var agent *kubernetes.Agent
  133. if app.ServerConf.IsTesting {
  134. agent = app.TestAgents.K8sAgent
  135. } else {
  136. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  137. }
  138. if err != nil {
  139. app.handleErrorInternal(err, w)
  140. return
  141. }
  142. namespace := &forms.NamespaceForm{
  143. Name: vals.Get("name"),
  144. }
  145. err = agent.DeleteNamespace(namespace.Name)
  146. if err != nil {
  147. app.handleErrorInternal(err, w)
  148. return
  149. }
  150. w.WriteHeader(http.StatusOK)
  151. return
  152. }
  153. // HandleListPodEvents retrieves all events tied to a pod.
  154. func (app *App) HandleListPodEvents(w http.ResponseWriter, r *http.Request) {
  155. vals, err := url.ParseQuery(r.URL.RawQuery)
  156. // get path parameters
  157. namespace := chi.URLParam(r, "namespace")
  158. name := chi.URLParam(r, "name")
  159. if err != nil {
  160. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  161. return
  162. }
  163. // get the filter options
  164. form := &forms.K8sForm{
  165. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  166. Repo: app.Repo,
  167. DigitalOceanOAuth: app.DOConf,
  168. },
  169. }
  170. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  171. // validate the form
  172. if err := app.validator.Struct(form); err != nil {
  173. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  174. return
  175. }
  176. // create a new agent
  177. var agent *kubernetes.Agent
  178. if app.ServerConf.IsTesting {
  179. agent = app.TestAgents.K8sAgent
  180. } else {
  181. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  182. }
  183. events, err := agent.ListEvents(name, namespace)
  184. if err != nil {
  185. app.handleErrorDataRead(err, w)
  186. return
  187. }
  188. if err := json.NewEncoder(w).Encode(events); err != nil {
  189. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  190. return
  191. }
  192. }
  193. func createConfigMap(agent *kubernetes.Agent, configMap *forms.ConfigMapForm) (*v1.ConfigMap, error) {
  194. secretData := make(map[string][]byte)
  195. for key, rawValue := range configMap.SecretEnvVariables {
  196. // encodedValue := base64.StdEncoding.EncodeToString([]byte(rawValue))
  197. // if err != nil {
  198. // app.handleErrorInternal(err, w)
  199. // return
  200. // }
  201. secretData[key] = []byte(rawValue)
  202. }
  203. // create secret first
  204. if _, err := agent.CreateLinkedSecret(configMap.Name, configMap.Namespace, configMap.Name, secretData); err != nil {
  205. return nil, err
  206. }
  207. // add all secret env variables to configmap with value PORTERSECRET_${configmap_name}
  208. for key, _ := range configMap.SecretEnvVariables {
  209. configMap.EnvVariables[key] = fmt.Sprintf("PORTERSECRET_%s", configMap.Name)
  210. }
  211. return agent.CreateConfigMap(configMap.Name, configMap.Namespace, configMap.EnvVariables)
  212. }
  213. // HandleCreateConfigMap creates a configmap (and secret) given the name, namespace and variables.
  214. func (app *App) HandleCreateConfigMap(w http.ResponseWriter, r *http.Request) {
  215. vals, err := url.ParseQuery(r.URL.RawQuery)
  216. if err != nil {
  217. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  218. return
  219. }
  220. // get the filter options
  221. form := &forms.K8sForm{
  222. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  223. Repo: app.Repo,
  224. DigitalOceanOAuth: app.DOConf,
  225. },
  226. }
  227. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  228. // validate the form
  229. if err := app.validator.Struct(form); err != nil {
  230. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  231. return
  232. }
  233. // create a new agent
  234. var agent *kubernetes.Agent
  235. if app.ServerConf.IsTesting {
  236. agent = app.TestAgents.K8sAgent
  237. } else {
  238. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  239. }
  240. configMapForm := &forms.ConfigMapForm{}
  241. if err := json.NewDecoder(r.Body).Decode(configMapForm); err != nil {
  242. app.handleErrorFormDecoding(err, ErrUserDecode, w)
  243. return
  244. }
  245. if _, err := createConfigMap(agent, configMapForm); err != nil {
  246. app.handleErrorInternal(err, w)
  247. return
  248. }
  249. if err := json.NewEncoder(w).Encode(configMapForm); err != nil {
  250. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  251. return
  252. }
  253. w.WriteHeader(http.StatusOK)
  254. return
  255. }
  256. // HandleListConfigMaps lists all configmaps in a namespace.
  257. func (app *App) HandleListConfigMaps(w http.ResponseWriter, r *http.Request) {
  258. vals, err := url.ParseQuery(r.URL.RawQuery)
  259. if err != nil {
  260. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  261. return
  262. }
  263. // get the filter options
  264. form := &forms.K8sForm{
  265. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  266. Repo: app.Repo,
  267. DigitalOceanOAuth: app.DOConf,
  268. },
  269. }
  270. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  271. // validate the form
  272. if err := app.validator.Struct(form); err != nil {
  273. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  274. return
  275. }
  276. // create a new agent
  277. var agent *kubernetes.Agent
  278. if app.ServerConf.IsTesting {
  279. agent = app.TestAgents.K8sAgent
  280. } else {
  281. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  282. }
  283. configMaps, err := agent.ListConfigMaps(vals["namespace"][0])
  284. if err != nil {
  285. app.handleErrorInternal(err, w)
  286. return
  287. }
  288. if err := json.NewEncoder(w).Encode(configMaps); err != nil {
  289. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  290. return
  291. }
  292. w.WriteHeader(http.StatusOK)
  293. return
  294. }
  295. // HandleGetConfigMap retreives the configmap given the name and namespace.
  296. func (app *App) HandleGetConfigMap(w http.ResponseWriter, r *http.Request) {
  297. vals, err := url.ParseQuery(r.URL.RawQuery)
  298. if err != nil {
  299. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  300. return
  301. }
  302. // get the filter options
  303. form := &forms.K8sForm{
  304. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  305. Repo: app.Repo,
  306. DigitalOceanOAuth: app.DOConf,
  307. },
  308. }
  309. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  310. // validate the form
  311. if err := app.validator.Struct(form); err != nil {
  312. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  313. return
  314. }
  315. // create a new agent
  316. var agent *kubernetes.Agent
  317. if app.ServerConf.IsTesting {
  318. agent = app.TestAgents.K8sAgent
  319. } else {
  320. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  321. }
  322. configMap, err := agent.GetConfigMap(vals["name"][0], vals["namespace"][0])
  323. if err != nil {
  324. app.handleErrorInternal(err, w)
  325. return
  326. }
  327. if err := json.NewEncoder(w).Encode(configMap); err != nil {
  328. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  329. return
  330. }
  331. w.WriteHeader(http.StatusOK)
  332. return
  333. }
  334. func deleteConfigMap(agent *kubernetes.Agent, name string, namespace string) error {
  335. if err := agent.DeleteLinkedSecret(name, namespace); err != nil {
  336. return err
  337. }
  338. if err := agent.DeleteConfigMap(name, namespace); err != nil {
  339. return err
  340. }
  341. return nil
  342. }
  343. // HandleDeleteConfigMap deletes the configmap (and secret) given the name and namespace.
  344. func (app *App) HandleDeleteConfigMap(w http.ResponseWriter, r *http.Request) {
  345. vals, err := url.ParseQuery(r.URL.RawQuery)
  346. if err != nil {
  347. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  348. return
  349. }
  350. // get the filter options
  351. form := &forms.K8sForm{
  352. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  353. Repo: app.Repo,
  354. DigitalOceanOAuth: app.DOConf,
  355. },
  356. }
  357. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  358. // validate the form
  359. if err := app.validator.Struct(form); err != nil {
  360. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  361. return
  362. }
  363. // create a new agent
  364. var agent *kubernetes.Agent
  365. if app.ServerConf.IsTesting {
  366. agent = app.TestAgents.K8sAgent
  367. } else {
  368. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  369. }
  370. if err := deleteConfigMap(agent, vals["name"][0], vals["namespace"][0]); err != nil {
  371. app.handleErrorInternal(err, w)
  372. return
  373. }
  374. w.WriteHeader(http.StatusOK)
  375. return
  376. }
  377. // HandleUpdateConfigMap updates the configmap (and secret) given the name, namespace and variables.
  378. func (app *App) HandleUpdateConfigMap(w http.ResponseWriter, r *http.Request) {
  379. vals, err := url.ParseQuery(r.URL.RawQuery)
  380. if err != nil {
  381. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  382. return
  383. }
  384. // get the filter options
  385. form := &forms.K8sForm{
  386. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  387. Repo: app.Repo,
  388. DigitalOceanOAuth: app.DOConf,
  389. },
  390. }
  391. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  392. // validate the form
  393. if err := app.validator.Struct(form); err != nil {
  394. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  395. return
  396. }
  397. // create a new agent
  398. var agent *kubernetes.Agent
  399. if app.ServerConf.IsTesting {
  400. agent = app.TestAgents.K8sAgent
  401. } else {
  402. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  403. }
  404. configMap := &forms.ConfigMapForm{}
  405. if err := json.NewDecoder(r.Body).Decode(configMap); err != nil {
  406. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  407. return
  408. }
  409. secretData := make(map[string][]byte)
  410. for key, rawValue := range configMap.SecretEnvVariables {
  411. // encodedValue, err := base64.StdEncoding.DecodeString(rawValue)
  412. // if err != nil {
  413. // app.handleErrorInternal(err, w)
  414. // return
  415. // }
  416. secretData[key] = []byte(rawValue)
  417. }
  418. // create secret first
  419. err = agent.UpdateLinkedSecret(configMap.Name, configMap.Namespace, configMap.Name, secretData)
  420. if err != nil {
  421. app.handleErrorInternal(err, w)
  422. return
  423. }
  424. // add all secret env variables to configmap with value PORTERSECRET_${configmap_name}
  425. for key, val := range configMap.SecretEnvVariables {
  426. // if val is empty and key does not exist in configmap already, set to empty
  427. if _, found := configMap.EnvVariables[key]; val == "" && !found {
  428. configMap.EnvVariables[key] = ""
  429. } else if val != "" {
  430. configMap.EnvVariables[key] = fmt.Sprintf("PORTERSECRET_%s", configMap.Name)
  431. }
  432. }
  433. err = agent.UpdateConfigMap(configMap.Name, configMap.Namespace, configMap.EnvVariables)
  434. if err != nil {
  435. app.handleErrorInternal(err, w)
  436. return
  437. }
  438. if err := json.NewEncoder(w).Encode(configMap); err != nil {
  439. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  440. return
  441. }
  442. w.WriteHeader(http.StatusOK)
  443. return
  444. }
  445. // HandleRenameConfigMap renames the configmap name given the current name, namespace and new name.
  446. func (app *App) HandleRenameConfigMap(w http.ResponseWriter, r *http.Request) {
  447. vals, err := url.ParseQuery(r.URL.RawQuery)
  448. if err != nil {
  449. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  450. return
  451. }
  452. // get the filter options
  453. form := &forms.K8sForm{
  454. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  455. Repo: app.Repo,
  456. DigitalOceanOAuth: app.DOConf,
  457. },
  458. }
  459. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  460. // validate the form
  461. if err := app.validator.Struct(form); err != nil {
  462. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  463. return
  464. }
  465. // create a new agent
  466. var agent *kubernetes.Agent
  467. if app.ServerConf.IsTesting {
  468. agent = app.TestAgents.K8sAgent
  469. } else {
  470. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  471. }
  472. renameConfigMapForm := &forms.RenameConfigMapForm{}
  473. if err := json.NewDecoder(r.Body).Decode(renameConfigMapForm); err != nil {
  474. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  475. return
  476. }
  477. configMap, err := agent.GetConfigMap(renameConfigMapForm.Name, renameConfigMapForm.Namespace)
  478. if err != nil {
  479. app.handleErrorInternal(err, w)
  480. return
  481. }
  482. secret, err := agent.GetSecret(configMap.Name, configMap.Namespace)
  483. if err != nil {
  484. app.handleErrorInternal(err, w)
  485. return
  486. }
  487. var decodedSecretData = make(map[string]string)
  488. for k, v := range secret.Data {
  489. decodedSecretData[k] = string(v)
  490. }
  491. newConfigMapForm := &forms.ConfigMapForm{
  492. Name: renameConfigMapForm.NewName,
  493. Namespace: configMap.Namespace,
  494. EnvVariables: configMap.Data,
  495. SecretEnvVariables: decodedSecretData,
  496. }
  497. if newConfigMapForm.Name == configMap.Name {
  498. w.WriteHeader(http.StatusBadRequest)
  499. return
  500. }
  501. newConfigMap, err := createConfigMap(agent, newConfigMapForm)
  502. if err != nil {
  503. app.handleErrorInternal(err, w)
  504. return
  505. }
  506. if err := deleteConfigMap(agent, configMap.Name, configMap.Namespace); err != nil {
  507. app.handleErrorInternal(err, w)
  508. return
  509. }
  510. if err := json.NewEncoder(w).Encode(newConfigMap); err != nil {
  511. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  512. return
  513. }
  514. w.WriteHeader(http.StatusOK)
  515. return
  516. }
  517. // HandleGetPodLogs returns real-time logs of the pod via websockets
  518. // TODO: Refactor repeated calls.
  519. func (app *App) HandleGetPodLogs(w http.ResponseWriter, r *http.Request) {
  520. // get session to retrieve correct kubeconfig
  521. _, err := app.Store.Get(r, app.ServerConf.CookieName)
  522. // get path parameters
  523. namespace := chi.URLParam(r, "namespace")
  524. podName := chi.URLParam(r, "name")
  525. if err != nil {
  526. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  527. return
  528. }
  529. vals, err := url.ParseQuery(r.URL.RawQuery)
  530. if err != nil {
  531. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  532. return
  533. }
  534. // get the filter options
  535. form := &forms.K8sForm{
  536. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  537. Repo: app.Repo,
  538. DigitalOceanOAuth: app.DOConf,
  539. },
  540. }
  541. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  542. // validate the form
  543. if err := app.validator.Struct(form); err != nil {
  544. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  545. return
  546. }
  547. // create a new agent
  548. var agent *kubernetes.Agent
  549. if app.ServerConf.IsTesting {
  550. agent = app.TestAgents.K8sAgent
  551. } else {
  552. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  553. }
  554. upgrader.CheckOrigin = func(r *http.Request) bool { return true }
  555. // upgrade to websocket.
  556. conn, err := upgrader.Upgrade(w, r, nil)
  557. if err != nil {
  558. app.handleErrorUpgradeWebsocket(err, w)
  559. }
  560. err = agent.GetPodLogs(namespace, podName, conn)
  561. if err != nil {
  562. app.handleErrorWebsocketWrite(err, w)
  563. return
  564. }
  565. }
  566. // HandleDeletePod deletes the pod given the name and namespace.
  567. func (app *App) HandleDeletePod(w http.ResponseWriter, r *http.Request) {
  568. // get path parameters
  569. namespace := chi.URLParam(r, "namespace")
  570. name := chi.URLParam(r, "name")
  571. vals, err := url.ParseQuery(r.URL.RawQuery)
  572. if err != nil {
  573. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  574. return
  575. }
  576. // get the filter options
  577. form := &forms.K8sForm{
  578. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  579. Repo: app.Repo,
  580. DigitalOceanOAuth: app.DOConf,
  581. },
  582. }
  583. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  584. // validate the form
  585. if err := app.validator.Struct(form); err != nil {
  586. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  587. return
  588. }
  589. // create a new agent
  590. var agent *kubernetes.Agent
  591. if app.ServerConf.IsTesting {
  592. agent = app.TestAgents.K8sAgent
  593. } else {
  594. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  595. }
  596. err = agent.DeletePod(namespace, name)
  597. if err != nil {
  598. app.handleErrorInternal(err, w)
  599. return
  600. }
  601. w.WriteHeader(http.StatusOK)
  602. return
  603. }
  604. // HandleGetIngress returns the ingress object given the name and namespace.
  605. func (app *App) HandleGetIngress(w http.ResponseWriter, r *http.Request) {
  606. // get session to retrieve correct kubeconfig
  607. _, err := app.Store.Get(r, app.ServerConf.CookieName)
  608. // get path parameters
  609. namespace := chi.URLParam(r, "namespace")
  610. name := chi.URLParam(r, "name")
  611. if err != nil {
  612. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  613. return
  614. }
  615. vals, err := url.ParseQuery(r.URL.RawQuery)
  616. if err != nil {
  617. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  618. return
  619. }
  620. // get the filter options
  621. form := &forms.K8sForm{
  622. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  623. Repo: app.Repo,
  624. DigitalOceanOAuth: app.DOConf,
  625. },
  626. }
  627. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  628. // validate the form
  629. if err := app.validator.Struct(form); err != nil {
  630. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  631. return
  632. }
  633. // create a new agent
  634. var agent *kubernetes.Agent
  635. if app.ServerConf.IsTesting {
  636. agent = app.TestAgents.K8sAgent
  637. } else {
  638. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  639. }
  640. ingress, err := agent.GetIngress(namespace, name)
  641. if err != nil {
  642. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  643. return
  644. }
  645. if err := json.NewEncoder(w).Encode(ingress); err != nil {
  646. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  647. return
  648. }
  649. }
  650. // HandleListPods returns all pods that match the given selectors
  651. // TODO: Refactor repeated calls.
  652. func (app *App) HandleListPods(w http.ResponseWriter, r *http.Request) {
  653. // get session to retrieve correct kubeconfig
  654. _, err := app.Store.Get(r, app.ServerConf.CookieName)
  655. if err != nil {
  656. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  657. return
  658. }
  659. vals, err := url.ParseQuery(r.URL.RawQuery)
  660. if err != nil {
  661. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  662. return
  663. }
  664. // get the filter options
  665. form := &forms.K8sForm{
  666. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  667. Repo: app.Repo,
  668. DigitalOceanOAuth: app.DOConf,
  669. },
  670. }
  671. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  672. // validate the form
  673. if err := app.validator.Struct(form); err != nil {
  674. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  675. return
  676. }
  677. // create a new agent
  678. var agent *kubernetes.Agent
  679. if app.ServerConf.IsTesting {
  680. agent = app.TestAgents.K8sAgent
  681. } else {
  682. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  683. }
  684. namespace := vals.Get("namespace")
  685. pods := []v1.Pod{}
  686. for _, selector := range vals["selectors"] {
  687. podsList, err := agent.GetPodsByLabel(selector, namespace)
  688. if err != nil {
  689. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  690. return
  691. }
  692. for _, pod := range podsList.Items {
  693. pods = append(pods, pod)
  694. }
  695. }
  696. if err := json.NewEncoder(w).Encode(pods); err != nil {
  697. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  698. return
  699. }
  700. }
  701. // HandleListJobsByChart lists all jobs belonging to a specific Helm chart
  702. func (app *App) HandleListJobsByChart(w http.ResponseWriter, r *http.Request) {
  703. // get path parameters
  704. namespace := chi.URLParam(r, "namespace")
  705. chart := chi.URLParam(r, "chart")
  706. releaseName := chi.URLParam(r, "release_name")
  707. vals, err := url.ParseQuery(r.URL.RawQuery)
  708. if err != nil {
  709. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  710. return
  711. }
  712. // get the filter options
  713. form := &forms.K8sForm{
  714. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  715. Repo: app.Repo,
  716. DigitalOceanOAuth: app.DOConf,
  717. },
  718. }
  719. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  720. // validate the form
  721. if err := app.validator.Struct(form); err != nil {
  722. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  723. return
  724. }
  725. // create a new agent
  726. var agent *kubernetes.Agent
  727. if app.ServerConf.IsTesting {
  728. agent = app.TestAgents.K8sAgent
  729. } else {
  730. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  731. }
  732. jobs, err := agent.ListJobsByLabel(namespace, kubernetes.Label{
  733. Key: "helm.sh/chart",
  734. Val: chart,
  735. }, kubernetes.Label{
  736. Key: "meta.helm.sh/release-name",
  737. Val: releaseName,
  738. })
  739. if err != nil {
  740. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  741. return
  742. }
  743. if err := json.NewEncoder(w).Encode(jobs); err != nil {
  744. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  745. return
  746. }
  747. }
  748. // HandleDeleteJob deletes the job given the name and namespace.
  749. func (app *App) HandleDeleteJob(w http.ResponseWriter, r *http.Request) {
  750. // get path parameters
  751. namespace := chi.URLParam(r, "namespace")
  752. name := chi.URLParam(r, "name")
  753. vals, err := url.ParseQuery(r.URL.RawQuery)
  754. if err != nil {
  755. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  756. return
  757. }
  758. // get the filter options
  759. form := &forms.K8sForm{
  760. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  761. Repo: app.Repo,
  762. DigitalOceanOAuth: app.DOConf,
  763. },
  764. }
  765. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  766. // validate the form
  767. if err := app.validator.Struct(form); err != nil {
  768. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  769. return
  770. }
  771. // create a new agent
  772. var agent *kubernetes.Agent
  773. if app.ServerConf.IsTesting {
  774. agent = app.TestAgents.K8sAgent
  775. } else {
  776. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  777. }
  778. err = agent.DeleteJob(name, namespace)
  779. if err != nil {
  780. app.handleErrorInternal(err, w)
  781. return
  782. }
  783. w.WriteHeader(http.StatusOK)
  784. return
  785. }
  786. // HandleStopJob stops a running job
  787. func (app *App) HandleStopJob(w http.ResponseWriter, r *http.Request) {
  788. // get path parameters
  789. namespace := chi.URLParam(r, "namespace")
  790. name := chi.URLParam(r, "name")
  791. vals, err := url.ParseQuery(r.URL.RawQuery)
  792. if err != nil {
  793. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  794. return
  795. }
  796. // get the filter options
  797. form := &forms.K8sForm{
  798. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  799. Repo: app.Repo,
  800. DigitalOceanOAuth: app.DOConf,
  801. },
  802. }
  803. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  804. // validate the form
  805. if err := app.validator.Struct(form); err != nil {
  806. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  807. return
  808. }
  809. // create a new agent
  810. var agent *kubernetes.Agent
  811. if app.ServerConf.IsTesting {
  812. agent = app.TestAgents.K8sAgent
  813. } else {
  814. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  815. }
  816. err = agent.StopJobWithJobSidecar(namespace, name)
  817. if err != nil {
  818. app.sendExternalError(err, 500, HTTPError{
  819. Code: 500,
  820. Errors: []string{err.Error()},
  821. }, w)
  822. return
  823. }
  824. w.WriteHeader(http.StatusOK)
  825. return
  826. }
  827. // HandleListJobPods lists all pods belonging to a specific job
  828. func (app *App) HandleListJobPods(w http.ResponseWriter, r *http.Request) {
  829. // get path parameters
  830. namespace := chi.URLParam(r, "namespace")
  831. name := chi.URLParam(r, "name")
  832. vals, err := url.ParseQuery(r.URL.RawQuery)
  833. if err != nil {
  834. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  835. return
  836. }
  837. // get the filter options
  838. form := &forms.K8sForm{
  839. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  840. Repo: app.Repo,
  841. DigitalOceanOAuth: app.DOConf,
  842. },
  843. }
  844. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  845. // validate the form
  846. if err := app.validator.Struct(form); err != nil {
  847. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  848. return
  849. }
  850. // create a new agent
  851. var agent *kubernetes.Agent
  852. if app.ServerConf.IsTesting {
  853. agent = app.TestAgents.K8sAgent
  854. } else {
  855. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  856. }
  857. pods, err := agent.GetJobPods(namespace, name)
  858. if err != nil {
  859. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  860. return
  861. }
  862. if err := json.NewEncoder(w).Encode(pods); err != nil {
  863. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  864. return
  865. }
  866. }
  867. // HandleStreamControllerStatus test calls
  868. // TODO: Refactor repeated calls.
  869. func (app *App) HandleStreamControllerStatus(w http.ResponseWriter, r *http.Request) {
  870. vals, err := url.ParseQuery(r.URL.RawQuery)
  871. if err != nil {
  872. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  873. return
  874. }
  875. // get session to retrieve correct kubeconfig
  876. _, err = app.Store.Get(r, app.ServerConf.CookieName)
  877. if err != nil {
  878. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  879. return
  880. }
  881. // get the filter options
  882. form := &forms.K8sForm{
  883. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  884. Repo: app.Repo,
  885. DigitalOceanOAuth: app.DOConf,
  886. },
  887. }
  888. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  889. // validate the form
  890. if err := app.validator.Struct(form); err != nil {
  891. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  892. return
  893. }
  894. // get path parameters
  895. kind := chi.URLParam(r, "kind")
  896. selectors := ""
  897. if vals["selectors"] != nil {
  898. selectors = vals["selectors"][0]
  899. }
  900. upgrader.CheckOrigin = func(r *http.Request) bool { return true }
  901. // upgrade to websocket.
  902. conn, err := upgrader.Upgrade(w, r, nil)
  903. if err != nil {
  904. app.handleErrorUpgradeWebsocket(err, w)
  905. }
  906. lastTime := int64(0)
  907. for {
  908. // create a new agent
  909. var agent *kubernetes.Agent
  910. if app.ServerConf.IsTesting {
  911. agent = app.TestAgents.K8sAgent
  912. } else {
  913. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  914. }
  915. err = agent.StreamControllerStatus(conn, kind, selectors)
  916. if err == nil {
  917. return
  918. }
  919. if !errors.Is(err, &kubernetes.AuthError{}) {
  920. app.handleErrorWebsocketWrite(err, w)
  921. return
  922. }
  923. if time.Now().Unix()-lastTime < 60 { // don't regenerate connection if too many unauthorized errors
  924. app.handleErrorWebsocketWrite(err, w)
  925. return
  926. }
  927. lastTime = time.Now().Unix()
  928. }
  929. }
  930. func (app *App) HandleStreamHelmReleases(w http.ResponseWriter, r *http.Request) {
  931. vals, err := url.ParseQuery(r.URL.RawQuery)
  932. if err != nil {
  933. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  934. return
  935. }
  936. // get session to retrieve correct kubeconfig
  937. _, err = app.Store.Get(r, app.ServerConf.CookieName)
  938. if err != nil {
  939. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  940. return
  941. }
  942. // get the filter options
  943. form := &forms.K8sForm{
  944. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  945. Repo: app.Repo,
  946. DigitalOceanOAuth: app.DOConf,
  947. },
  948. }
  949. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  950. // validate the form
  951. if err := app.validator.Struct(form); err != nil {
  952. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  953. return
  954. }
  955. // create a new agent
  956. var agent *kubernetes.Agent
  957. if app.ServerConf.IsTesting {
  958. agent = app.TestAgents.K8sAgent
  959. } else {
  960. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  961. }
  962. upgrader.CheckOrigin = func(r *http.Request) bool { return true }
  963. // upgrade to websocket.
  964. conn, err := upgrader.Upgrade(w, r, nil)
  965. if err != nil {
  966. app.handleErrorUpgradeWebsocket(err, w)
  967. }
  968. selectors := ""
  969. if vals["selectors"] != nil {
  970. selectors = vals["selectors"][0]
  971. }
  972. var chartList []string
  973. if vals["charts"] != nil {
  974. chartList = vals["charts"]
  975. }
  976. namespace := v1.NamespaceAll
  977. if vals["namespace"] != nil {
  978. namespace = vals["namespace"][0]
  979. }
  980. err = agent.StreamHelmReleases(conn, namespace, chartList, selectors)
  981. if err != nil {
  982. app.handleErrorWebsocketWrite(err, w)
  983. return
  984. }
  985. }
  986. // HandleDetectPrometheusInstalled detects a prometheus installation in the target cluster
  987. func (app *App) HandleDetectPrometheusInstalled(w http.ResponseWriter, r *http.Request) {
  988. vals, err := url.ParseQuery(r.URL.RawQuery)
  989. if err != nil {
  990. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  991. return
  992. }
  993. // get the filter options
  994. form := &forms.K8sForm{
  995. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  996. Repo: app.Repo,
  997. DigitalOceanOAuth: app.DOConf,
  998. },
  999. }
  1000. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  1001. // validate the form
  1002. if err := app.validator.Struct(form); err != nil {
  1003. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  1004. return
  1005. }
  1006. // create a new agent
  1007. var agent *kubernetes.Agent
  1008. if app.ServerConf.IsTesting {
  1009. agent = app.TestAgents.K8sAgent
  1010. } else {
  1011. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  1012. }
  1013. // detect prometheus service
  1014. _, found, err := prometheus.GetPrometheusService(agent.Clientset)
  1015. if !found {
  1016. http.NotFound(w, r)
  1017. return
  1018. }
  1019. w.WriteHeader(http.StatusOK)
  1020. return
  1021. }
  1022. // HandleListNGINXIngresses lists all NGINX ingresses in a target cluster
  1023. func (app *App) HandleListNGINXIngresses(w http.ResponseWriter, r *http.Request) {
  1024. vals, err := url.ParseQuery(r.URL.RawQuery)
  1025. if err != nil {
  1026. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  1027. return
  1028. }
  1029. // get the filter options
  1030. form := &forms.K8sForm{
  1031. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  1032. Repo: app.Repo,
  1033. DigitalOceanOAuth: app.DOConf,
  1034. },
  1035. }
  1036. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  1037. // validate the form
  1038. if err := app.validator.Struct(form); err != nil {
  1039. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  1040. return
  1041. }
  1042. // create a new agent
  1043. var agent *kubernetes.Agent
  1044. if app.ServerConf.IsTesting {
  1045. agent = app.TestAgents.K8sAgent
  1046. } else {
  1047. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  1048. }
  1049. res, err := prometheus.GetIngressesWithNGINXAnnotation(agent.Clientset)
  1050. if err != nil {
  1051. app.handleErrorInternal(err, w)
  1052. return
  1053. }
  1054. w.WriteHeader(http.StatusOK)
  1055. if err := json.NewEncoder(w).Encode(res); err != nil {
  1056. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  1057. return
  1058. }
  1059. }
  1060. func (app *App) HandleGetPodMetrics(w http.ResponseWriter, r *http.Request) {
  1061. vals, err := url.ParseQuery(r.URL.RawQuery)
  1062. if err != nil {
  1063. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  1064. return
  1065. }
  1066. // get the filter options
  1067. form := &forms.MetricsQueryForm{
  1068. K8sForm: &forms.K8sForm{
  1069. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  1070. Repo: app.Repo,
  1071. DigitalOceanOAuth: app.DOConf,
  1072. },
  1073. },
  1074. QueryOpts: &prometheus.QueryOpts{},
  1075. }
  1076. form.K8sForm.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  1077. // decode from JSON to form value
  1078. decoder := schema.NewDecoder()
  1079. decoder.IgnoreUnknownKeys(true)
  1080. if err := decoder.Decode(form.QueryOpts, vals); err != nil {
  1081. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  1082. return
  1083. }
  1084. // validate the form
  1085. if err := app.validator.Struct(form); err != nil {
  1086. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  1087. return
  1088. }
  1089. // create a new agent
  1090. var agent *kubernetes.Agent
  1091. if app.ServerConf.IsTesting {
  1092. agent = app.TestAgents.K8sAgent
  1093. } else {
  1094. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  1095. }
  1096. // get prometheus service
  1097. promSvc, found, err := prometheus.GetPrometheusService(agent.Clientset)
  1098. if err != nil {
  1099. app.handleErrorInternal(err, w)
  1100. return
  1101. }
  1102. if !found {
  1103. app.handleErrorInternal(err, w)
  1104. return
  1105. }
  1106. rawQuery, err := prometheus.QueryPrometheus(agent.Clientset, promSvc, form.QueryOpts)
  1107. if err != nil {
  1108. app.handleErrorInternal(err, w)
  1109. return
  1110. }
  1111. fmt.Fprint(w, string(rawQuery))
  1112. }
  1113. type KubeconfigResponse struct {
  1114. Kubeconfig []byte `json:"kubeconfig"`
  1115. }
  1116. func (app *App) HandleGetTemporaryKubeconfig(w http.ResponseWriter, r *http.Request) {
  1117. vals, err := url.ParseQuery(r.URL.RawQuery)
  1118. if err != nil {
  1119. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  1120. return
  1121. }
  1122. // get the filter options
  1123. form := &forms.K8sForm{
  1124. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  1125. Repo: app.Repo,
  1126. DigitalOceanOAuth: app.DOConf,
  1127. },
  1128. }
  1129. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  1130. // get the API config
  1131. apiConf, err := form.OutOfClusterConfig.CreateRawConfigFromCluster()
  1132. if err != nil {
  1133. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  1134. return
  1135. }
  1136. bytes, err := clientcmd.Write(*apiConf)
  1137. res := &KubeconfigResponse{
  1138. Kubeconfig: bytes,
  1139. }
  1140. if err := json.NewEncoder(w).Encode(res); err != nil {
  1141. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  1142. return
  1143. }
  1144. }
  1145. func (app *App) HandleListNodes(w http.ResponseWriter, r *http.Request) {
  1146. id, err := strconv.ParseUint(chi.URLParam(r, "cluster_id"), 0, 64)
  1147. if err != nil || id == 0 {
  1148. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  1149. return
  1150. }
  1151. cluster, err := app.Repo.Cluster.ReadCluster(uint(id))
  1152. if err != nil {
  1153. app.handleErrorRead(err, ErrProjectDataRead, w)
  1154. return
  1155. }
  1156. form := &forms.K8sForm{
  1157. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  1158. Repo: app.Repo,
  1159. DigitalOceanOAuth: app.DOConf,
  1160. Cluster: cluster,
  1161. },
  1162. }
  1163. var agent *kubernetes.Agent
  1164. if app.ServerConf.IsTesting {
  1165. agent = app.TestAgents.K8sAgent
  1166. } else {
  1167. agent, _ = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  1168. }
  1169. nodeWithUsageList := nodes.GetNodesUsage(agent.Clientset)
  1170. w.WriteHeader(http.StatusOK)
  1171. if err := json.NewEncoder(w).Encode(nodeWithUsageList); err != nil {
  1172. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  1173. return
  1174. }
  1175. }
  1176. func (app *App) HandleGetNode(w http.ResponseWriter, r *http.Request) {
  1177. cluster_id, err := strconv.ParseUint(chi.URLParam(r, "cluster_id"), 0, 64)
  1178. node_name := chi.URLParam(r, "node_name")
  1179. if err != nil || cluster_id == 0 {
  1180. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  1181. return
  1182. }
  1183. cluster, err := app.Repo.Cluster.ReadCluster(uint(cluster_id))
  1184. if err != nil {
  1185. app.handleErrorRead(err, ErrProjectDataRead, w)
  1186. return
  1187. }
  1188. form := &forms.K8sForm{
  1189. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  1190. Repo: app.Repo,
  1191. DigitalOceanOAuth: app.DOConf,
  1192. Cluster: cluster,
  1193. },
  1194. }
  1195. var agent *kubernetes.Agent
  1196. if app.ServerConf.IsTesting {
  1197. agent = app.TestAgents.K8sAgent
  1198. } else {
  1199. agent, _ = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  1200. }
  1201. nodeWithUsageData := nodes.DescribeNode(agent.Clientset, node_name)
  1202. w.WriteHeader(http.StatusOK)
  1203. if err := json.NewEncoder(w).Encode(nodeWithUsageData); err != nil {
  1204. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  1205. return
  1206. }
  1207. }