k8s_handler.go 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527
  1. package api
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "net/url"
  7. "strconv"
  8. "github.com/go-chi/chi"
  9. "github.com/gorilla/schema"
  10. "github.com/gorilla/websocket"
  11. "github.com/porter-dev/porter/internal/forms"
  12. "github.com/porter-dev/porter/internal/kubernetes"
  13. "github.com/porter-dev/porter/internal/kubernetes/nodes"
  14. "github.com/porter-dev/porter/internal/kubernetes/prometheus"
  15. v1 "k8s.io/api/core/v1"
  16. "k8s.io/client-go/tools/clientcmd"
  17. )
  18. // Enumeration of k8s API error codes, represented as int64
  19. const (
  20. ErrK8sDecode ErrorCode = iota + 600
  21. ErrK8sValidate
  22. ErrEnvDecode
  23. )
  24. var upgrader = websocket.Upgrader{
  25. ReadBufferSize: 1024,
  26. WriteBufferSize: 1024,
  27. }
  28. // HandleListNamespaces retrieves a list of namespaces
  29. func (app *App) HandleListNamespaces(w http.ResponseWriter, r *http.Request) {
  30. vals, err := url.ParseQuery(r.URL.RawQuery)
  31. if err != nil {
  32. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  33. return
  34. }
  35. // get the filter options
  36. form := &forms.K8sForm{
  37. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  38. Repo: app.Repo,
  39. DigitalOceanOAuth: app.DOConf,
  40. },
  41. }
  42. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  43. // validate the form
  44. if err := app.validator.Struct(form); err != nil {
  45. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  46. return
  47. }
  48. // create a new agent
  49. var agent *kubernetes.Agent
  50. if app.ServerConf.IsTesting {
  51. agent = app.TestAgents.K8sAgent
  52. } else {
  53. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  54. }
  55. namespaces, err := agent.ListNamespaces()
  56. if err != nil {
  57. app.handleErrorDataRead(err, w)
  58. return
  59. }
  60. if err := json.NewEncoder(w).Encode(namespaces); err != nil {
  61. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  62. return
  63. }
  64. }
  65. // HandleCreateNamespace creates a new namespace given the name.
  66. func (app *App) HandleCreateNamespace(w http.ResponseWriter, r *http.Request) {
  67. vals, err := url.ParseQuery(r.URL.RawQuery)
  68. if err != nil {
  69. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  70. return
  71. }
  72. // get the filter options
  73. form := &forms.K8sForm{
  74. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  75. Repo: app.Repo,
  76. DigitalOceanOAuth: app.DOConf,
  77. },
  78. }
  79. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  80. // validate the form
  81. if err := app.validator.Struct(form); err != nil {
  82. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  83. return
  84. }
  85. // create a new agent
  86. var agent *kubernetes.Agent
  87. if app.ServerConf.IsTesting {
  88. agent = app.TestAgents.K8sAgent
  89. } else {
  90. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  91. }
  92. ns := &forms.NamespaceForm{}
  93. if err := json.NewDecoder(r.Body).Decode(ns); err != nil {
  94. app.handleErrorFormDecoding(err, ErrUserDecode, w)
  95. return
  96. }
  97. namespace, err := agent.CreateNamespace(ns.Name)
  98. if err != nil {
  99. app.handleErrorInternal(err, w)
  100. return
  101. }
  102. if err := json.NewEncoder(w).Encode(namespace); err != nil {
  103. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  104. return
  105. }
  106. w.WriteHeader(http.StatusOK)
  107. return
  108. }
  109. // HandleDeleteNamespace deletes a namespace given the name.
  110. func (app *App) HandleDeleteNamespace(w http.ResponseWriter, r *http.Request) {
  111. vals, err := url.ParseQuery(r.URL.RawQuery)
  112. if err != nil {
  113. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  114. return
  115. }
  116. // get the filter options
  117. form := &forms.K8sForm{
  118. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  119. Repo: app.Repo,
  120. DigitalOceanOAuth: app.DOConf,
  121. },
  122. }
  123. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  124. // validate the form
  125. if err := app.validator.Struct(form); err != nil {
  126. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  127. return
  128. }
  129. // create a new agent
  130. var agent *kubernetes.Agent
  131. if app.ServerConf.IsTesting {
  132. agent = app.TestAgents.K8sAgent
  133. } else {
  134. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  135. }
  136. if err != nil {
  137. app.handleErrorInternal(err, w)
  138. return
  139. }
  140. namespace := &forms.NamespaceForm{
  141. Name: vals.Get("name"),
  142. }
  143. err = agent.DeleteNamespace(namespace.Name)
  144. if err != nil {
  145. app.handleErrorInternal(err, w)
  146. return
  147. }
  148. w.WriteHeader(http.StatusOK)
  149. return
  150. }
  151. // HandleListPodEvents retrieves all events tied to a pod.
  152. func (app *App) HandleListPodEvents(w http.ResponseWriter, r *http.Request) {
  153. vals, err := url.ParseQuery(r.URL.RawQuery)
  154. // get path parameters
  155. namespace := chi.URLParam(r, "namespace")
  156. name := chi.URLParam(r, "name")
  157. if err != nil {
  158. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  159. return
  160. }
  161. // get the filter options
  162. form := &forms.K8sForm{
  163. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  164. Repo: app.Repo,
  165. DigitalOceanOAuth: app.DOConf,
  166. },
  167. }
  168. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  169. // validate the form
  170. if err := app.validator.Struct(form); err != nil {
  171. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  172. return
  173. }
  174. // create a new agent
  175. var agent *kubernetes.Agent
  176. if app.ServerConf.IsTesting {
  177. agent = app.TestAgents.K8sAgent
  178. } else {
  179. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  180. }
  181. events, err := agent.ListEvents(name, namespace)
  182. if err != nil {
  183. app.handleErrorDataRead(err, w)
  184. return
  185. }
  186. if err := json.NewEncoder(w).Encode(events); err != nil {
  187. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  188. return
  189. }
  190. }
  191. func createConfigMap(agent *kubernetes.Agent, configMap *forms.ConfigMapForm) error {
  192. secretData := make(map[string][]byte)
  193. for key, rawValue := range configMap.SecretEnvVariables {
  194. // encodedValue := base64.StdEncoding.EncodeToString([]byte(rawValue))
  195. // if err != nil {
  196. // app.handleErrorInternal(err, w)
  197. // return
  198. // }
  199. secretData[key] = []byte(rawValue)
  200. }
  201. // create secret first
  202. if _, err := agent.CreateLinkedSecret(configMap.Name, configMap.Namespace, configMap.Name, secretData); err != nil {
  203. return err
  204. }
  205. // add all secret env variables to configmap with value PORTERSECRET_${configmap_name}
  206. for key, _ := range configMap.SecretEnvVariables {
  207. configMap.EnvVariables[key] = fmt.Sprintf("PORTERSECRET_%s", configMap.Name)
  208. }
  209. if _, err := agent.CreateConfigMap(configMap.Name, configMap.Namespace, configMap.EnvVariables); err != nil {
  210. return err
  211. }
  212. return nil
  213. }
  214. // HandleCreateConfigMap creates a configmap (and secret) given the name, namespace and variables.
  215. func (app *App) HandleCreateConfigMap(w http.ResponseWriter, r *http.Request) {
  216. vals, err := url.ParseQuery(r.URL.RawQuery)
  217. if err != nil {
  218. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  219. return
  220. }
  221. // get the filter options
  222. form := &forms.K8sForm{
  223. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  224. Repo: app.Repo,
  225. DigitalOceanOAuth: app.DOConf,
  226. },
  227. }
  228. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  229. // validate the form
  230. if err := app.validator.Struct(form); err != nil {
  231. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  232. return
  233. }
  234. // create a new agent
  235. var agent *kubernetes.Agent
  236. if app.ServerConf.IsTesting {
  237. agent = app.TestAgents.K8sAgent
  238. } else {
  239. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  240. }
  241. configMap := &forms.ConfigMapForm{}
  242. if err := json.NewDecoder(r.Body).Decode(configMap); err != nil {
  243. app.handleErrorFormDecoding(err, ErrUserDecode, w)
  244. return
  245. }
  246. if err := createConfigMap(agent, configMap); err != nil {
  247. app.handleErrorInternal(err, w)
  248. return
  249. }
  250. if err := json.NewEncoder(w).Encode(configMap); err != nil {
  251. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  252. return
  253. }
  254. w.WriteHeader(http.StatusOK)
  255. return
  256. }
  257. // HandleListConfigMaps lists all configmaps in a namespace.
  258. func (app *App) HandleListConfigMaps(w http.ResponseWriter, r *http.Request) {
  259. vals, err := url.ParseQuery(r.URL.RawQuery)
  260. if err != nil {
  261. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  262. return
  263. }
  264. // get the filter options
  265. form := &forms.K8sForm{
  266. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  267. Repo: app.Repo,
  268. DigitalOceanOAuth: app.DOConf,
  269. },
  270. }
  271. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  272. // validate the form
  273. if err := app.validator.Struct(form); err != nil {
  274. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  275. return
  276. }
  277. // create a new agent
  278. var agent *kubernetes.Agent
  279. if app.ServerConf.IsTesting {
  280. agent = app.TestAgents.K8sAgent
  281. } else {
  282. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  283. }
  284. configMaps, err := agent.ListConfigMaps(vals["namespace"][0])
  285. if err != nil {
  286. app.handleErrorInternal(err, w)
  287. return
  288. }
  289. if err := json.NewEncoder(w).Encode(configMaps); err != nil {
  290. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  291. return
  292. }
  293. w.WriteHeader(http.StatusOK)
  294. return
  295. }
  296. // HandleGetConfigMap retreives the configmap given the name and namespace.
  297. func (app *App) HandleGetConfigMap(w http.ResponseWriter, r *http.Request) {
  298. vals, err := url.ParseQuery(r.URL.RawQuery)
  299. if err != nil {
  300. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  301. return
  302. }
  303. // get the filter options
  304. form := &forms.K8sForm{
  305. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  306. Repo: app.Repo,
  307. DigitalOceanOAuth: app.DOConf,
  308. },
  309. }
  310. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  311. // validate the form
  312. if err := app.validator.Struct(form); err != nil {
  313. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  314. return
  315. }
  316. // create a new agent
  317. var agent *kubernetes.Agent
  318. if app.ServerConf.IsTesting {
  319. agent = app.TestAgents.K8sAgent
  320. } else {
  321. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  322. }
  323. configMap, err := agent.GetConfigMap(vals["name"][0], vals["namespace"][0])
  324. if err != nil {
  325. app.handleErrorInternal(err, w)
  326. return
  327. }
  328. if err := json.NewEncoder(w).Encode(configMap); err != nil {
  329. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  330. return
  331. }
  332. w.WriteHeader(http.StatusOK)
  333. return
  334. }
  335. func deleteConfigMap(agent *kubernetes.Agent, name string, namespace string) error {
  336. if err := agent.DeleteLinkedSecret(name, namespace); err != nil {
  337. return err
  338. }
  339. if err := agent.DeleteConfigMap(name, namespace); err != nil {
  340. return err
  341. }
  342. return nil
  343. }
  344. // HandleDeleteConfigMap deletes the configmap (and secret) given the name and namespace.
  345. func (app *App) HandleDeleteConfigMap(w http.ResponseWriter, r *http.Request) {
  346. vals, err := url.ParseQuery(r.URL.RawQuery)
  347. if err != nil {
  348. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  349. return
  350. }
  351. // get the filter options
  352. form := &forms.K8sForm{
  353. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  354. Repo: app.Repo,
  355. DigitalOceanOAuth: app.DOConf,
  356. },
  357. }
  358. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  359. // validate the form
  360. if err := app.validator.Struct(form); err != nil {
  361. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  362. return
  363. }
  364. // create a new agent
  365. var agent *kubernetes.Agent
  366. if app.ServerConf.IsTesting {
  367. agent = app.TestAgents.K8sAgent
  368. } else {
  369. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  370. }
  371. if err := deleteConfigMap(agent, vals["name"][0], vals["namespace"][0]); err != nil {
  372. app.handleErrorInternal(err, w)
  373. return
  374. }
  375. w.WriteHeader(http.StatusOK)
  376. return
  377. }
  378. // HandleUpdateConfigMap updates the configmap (and secret) given the name, namespace and variables.
  379. func (app *App) HandleUpdateConfigMap(w http.ResponseWriter, r *http.Request) {
  380. vals, err := url.ParseQuery(r.URL.RawQuery)
  381. if err != nil {
  382. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  383. return
  384. }
  385. // get the filter options
  386. form := &forms.K8sForm{
  387. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  388. Repo: app.Repo,
  389. DigitalOceanOAuth: app.DOConf,
  390. },
  391. }
  392. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  393. // validate the form
  394. if err := app.validator.Struct(form); err != nil {
  395. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  396. return
  397. }
  398. // create a new agent
  399. var agent *kubernetes.Agent
  400. if app.ServerConf.IsTesting {
  401. agent = app.TestAgents.K8sAgent
  402. } else {
  403. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  404. }
  405. configMap := &forms.ConfigMapForm{}
  406. if err := json.NewDecoder(r.Body).Decode(configMap); err != nil {
  407. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  408. return
  409. }
  410. secretData := make(map[string][]byte)
  411. for key, rawValue := range configMap.SecretEnvVariables {
  412. // encodedValue, err := base64.StdEncoding.DecodeString(rawValue)
  413. // if err != nil {
  414. // app.handleErrorInternal(err, w)
  415. // return
  416. // }
  417. secretData[key] = []byte(rawValue)
  418. }
  419. // create secret first
  420. err = agent.UpdateLinkedSecret(configMap.Name, configMap.Namespace, configMap.Name, secretData)
  421. if err != nil {
  422. app.handleErrorInternal(err, w)
  423. return
  424. }
  425. // add all secret env variables to configmap with value PORTERSECRET_${configmap_name}
  426. for key, val := range configMap.SecretEnvVariables {
  427. // if val is empty and key does not exist in configmap already, set to empty
  428. if _, found := configMap.EnvVariables[key]; val == "" && !found {
  429. configMap.EnvVariables[key] = ""
  430. } else if val != "" {
  431. configMap.EnvVariables[key] = fmt.Sprintf("PORTERSECRET_%s", configMap.Name)
  432. }
  433. }
  434. err = agent.UpdateConfigMap(configMap.Name, configMap.Namespace, configMap.EnvVariables)
  435. if err != nil {
  436. app.handleErrorInternal(err, w)
  437. return
  438. }
  439. if err := json.NewEncoder(w).Encode(configMap); err != nil {
  440. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  441. return
  442. }
  443. w.WriteHeader(http.StatusOK)
  444. return
  445. }
  446. // HandleRenameConfigMap renames the configmap name given the current name, namespace and new name.
  447. func (app *App) HandleRenameConfigMap(w http.ResponseWriter, r *http.Request) {
  448. vals, err := url.ParseQuery(r.URL.RawQuery)
  449. if err != nil {
  450. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  451. return
  452. }
  453. // get the filter options
  454. form := &forms.K8sForm{
  455. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  456. Repo: app.Repo,
  457. DigitalOceanOAuth: app.DOConf,
  458. },
  459. }
  460. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  461. // validate the form
  462. if err := app.validator.Struct(form); err != nil {
  463. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  464. return
  465. }
  466. // create a new agent
  467. var agent *kubernetes.Agent
  468. if app.ServerConf.IsTesting {
  469. agent = app.TestAgents.K8sAgent
  470. } else {
  471. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  472. }
  473. renameConfigMapForm := &forms.RenameConfigMapForm{}
  474. if err := json.NewDecoder(r.Body).Decode(renameConfigMapForm); err != nil {
  475. app.handleErrorFormDecoding(err, ErrEnvDecode, w)
  476. return
  477. }
  478. configMap, err := agent.GetConfigMap(renameConfigMapForm.Name, renameConfigMapForm.Namespace)
  479. if err != nil {
  480. app.handleErrorInternal(err, w)
  481. return
  482. }
  483. secret, err := agent.GetSecret(configMap.Name, configMap.Namespace)
  484. if err != nil {
  485. app.handleErrorInternal(err, w)
  486. return
  487. }
  488. var decodedSecretData = make(map[string]string)
  489. for k, v := range secret.Data {
  490. decodedSecretData[k] = string(v)
  491. }
  492. newConfigMap := &forms.ConfigMapForm{
  493. Name: renameConfigMapForm.NewName,
  494. Namespace: configMap.Namespace,
  495. EnvVariables: configMap.Data,
  496. SecretEnvVariables: decodedSecretData,
  497. }
  498. if newConfigMap.Name == configMap.Name {
  499. w.WriteHeader(http.StatusBadRequest)
  500. return
  501. }
  502. if err := createConfigMap(agent, newConfigMap); 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. // create a new agent
  895. var agent *kubernetes.Agent
  896. if app.ServerConf.IsTesting {
  897. agent = app.TestAgents.K8sAgent
  898. } else {
  899. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  900. }
  901. upgrader.CheckOrigin = func(r *http.Request) bool { return true }
  902. // upgrade to websocket.
  903. conn, err := upgrader.Upgrade(w, r, nil)
  904. if err != nil {
  905. app.handleErrorUpgradeWebsocket(err, w)
  906. }
  907. // get path parameters
  908. kind := chi.URLParam(r, "kind")
  909. selectors := ""
  910. if vals["selectors"] != nil {
  911. selectors = vals["selectors"][0]
  912. }
  913. err = agent.StreamControllerStatus(conn, kind, selectors)
  914. if err != nil {
  915. app.handleErrorWebsocketWrite(err, w)
  916. return
  917. }
  918. }
  919. func (app *App) HandleStreamHelmReleases(w http.ResponseWriter, r *http.Request) {
  920. vals, err := url.ParseQuery(r.URL.RawQuery)
  921. if err != nil {
  922. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  923. return
  924. }
  925. // get session to retrieve correct kubeconfig
  926. _, err = app.Store.Get(r, app.ServerConf.CookieName)
  927. if err != nil {
  928. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  929. return
  930. }
  931. // get the filter options
  932. form := &forms.K8sForm{
  933. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  934. Repo: app.Repo,
  935. DigitalOceanOAuth: app.DOConf,
  936. },
  937. }
  938. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  939. // validate the form
  940. if err := app.validator.Struct(form); err != nil {
  941. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  942. return
  943. }
  944. // create a new agent
  945. var agent *kubernetes.Agent
  946. if app.ServerConf.IsTesting {
  947. agent = app.TestAgents.K8sAgent
  948. } else {
  949. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  950. }
  951. upgrader.CheckOrigin = func(r *http.Request) bool { return true }
  952. // upgrade to websocket.
  953. conn, err := upgrader.Upgrade(w, r, nil)
  954. if err != nil {
  955. app.handleErrorUpgradeWebsocket(err, w)
  956. }
  957. selectors := ""
  958. if vals["selectors"] != nil {
  959. selectors = vals["selectors"][0]
  960. }
  961. var chartList []string
  962. if vals["charts"] != nil {
  963. chartList = vals["charts"]
  964. }
  965. err = agent.StreamHelmReleases(conn, chartList, selectors)
  966. if err != nil {
  967. app.handleErrorWebsocketWrite(err, w)
  968. return
  969. }
  970. }
  971. // HandleDetectPrometheusInstalled detects a prometheus installation in the target cluster
  972. func (app *App) HandleDetectPrometheusInstalled(w http.ResponseWriter, r *http.Request) {
  973. vals, err := url.ParseQuery(r.URL.RawQuery)
  974. if err != nil {
  975. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  976. return
  977. }
  978. // get the filter options
  979. form := &forms.K8sForm{
  980. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  981. Repo: app.Repo,
  982. DigitalOceanOAuth: app.DOConf,
  983. },
  984. }
  985. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  986. // validate the form
  987. if err := app.validator.Struct(form); err != nil {
  988. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  989. return
  990. }
  991. // create a new agent
  992. var agent *kubernetes.Agent
  993. if app.ServerConf.IsTesting {
  994. agent = app.TestAgents.K8sAgent
  995. } else {
  996. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  997. }
  998. // detect prometheus service
  999. _, found, err := prometheus.GetPrometheusService(agent.Clientset)
  1000. if !found {
  1001. http.NotFound(w, r)
  1002. return
  1003. }
  1004. w.WriteHeader(http.StatusOK)
  1005. return
  1006. }
  1007. // HandleListNGINXIngresses lists all NGINX ingresses in a target cluster
  1008. func (app *App) HandleListNGINXIngresses(w http.ResponseWriter, r *http.Request) {
  1009. vals, err := url.ParseQuery(r.URL.RawQuery)
  1010. if err != nil {
  1011. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  1012. return
  1013. }
  1014. // get the filter options
  1015. form := &forms.K8sForm{
  1016. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  1017. Repo: app.Repo,
  1018. DigitalOceanOAuth: app.DOConf,
  1019. },
  1020. }
  1021. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  1022. // validate the form
  1023. if err := app.validator.Struct(form); err != nil {
  1024. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  1025. return
  1026. }
  1027. // create a new agent
  1028. var agent *kubernetes.Agent
  1029. if app.ServerConf.IsTesting {
  1030. agent = app.TestAgents.K8sAgent
  1031. } else {
  1032. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  1033. }
  1034. res, err := prometheus.GetIngressesWithNGINXAnnotation(agent.Clientset)
  1035. if err != nil {
  1036. app.handleErrorInternal(err, w)
  1037. return
  1038. }
  1039. w.WriteHeader(http.StatusOK)
  1040. if err := json.NewEncoder(w).Encode(res); err != nil {
  1041. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  1042. return
  1043. }
  1044. }
  1045. func (app *App) HandleGetPodMetrics(w http.ResponseWriter, r *http.Request) {
  1046. vals, err := url.ParseQuery(r.URL.RawQuery)
  1047. if err != nil {
  1048. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  1049. return
  1050. }
  1051. // get the filter options
  1052. form := &forms.MetricsQueryForm{
  1053. K8sForm: &forms.K8sForm{
  1054. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  1055. Repo: app.Repo,
  1056. DigitalOceanOAuth: app.DOConf,
  1057. },
  1058. },
  1059. QueryOpts: &prometheus.QueryOpts{},
  1060. }
  1061. form.K8sForm.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  1062. // decode from JSON to form value
  1063. decoder := schema.NewDecoder()
  1064. decoder.IgnoreUnknownKeys(true)
  1065. if err := decoder.Decode(form.QueryOpts, vals); err != nil {
  1066. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  1067. return
  1068. }
  1069. // validate the form
  1070. if err := app.validator.Struct(form); err != nil {
  1071. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  1072. return
  1073. }
  1074. // create a new agent
  1075. var agent *kubernetes.Agent
  1076. if app.ServerConf.IsTesting {
  1077. agent = app.TestAgents.K8sAgent
  1078. } else {
  1079. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  1080. }
  1081. // get prometheus service
  1082. promSvc, found, err := prometheus.GetPrometheusService(agent.Clientset)
  1083. if err != nil {
  1084. app.handleErrorInternal(err, w)
  1085. return
  1086. }
  1087. if !found {
  1088. app.handleErrorInternal(err, w)
  1089. return
  1090. }
  1091. rawQuery, err := prometheus.QueryPrometheus(agent.Clientset, promSvc, form.QueryOpts)
  1092. if err != nil {
  1093. app.handleErrorInternal(err, w)
  1094. return
  1095. }
  1096. fmt.Fprint(w, string(rawQuery))
  1097. }
  1098. type KubeconfigResponse struct {
  1099. Kubeconfig []byte `json:"kubeconfig"`
  1100. }
  1101. func (app *App) HandleGetTemporaryKubeconfig(w http.ResponseWriter, r *http.Request) {
  1102. vals, err := url.ParseQuery(r.URL.RawQuery)
  1103. if err != nil {
  1104. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  1105. return
  1106. }
  1107. // get the filter options
  1108. form := &forms.K8sForm{
  1109. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  1110. Repo: app.Repo,
  1111. DigitalOceanOAuth: app.DOConf,
  1112. },
  1113. }
  1114. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  1115. // get the API config
  1116. apiConf, err := form.OutOfClusterConfig.CreateRawConfigFromCluster()
  1117. if err != nil {
  1118. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  1119. return
  1120. }
  1121. bytes, err := clientcmd.Write(*apiConf)
  1122. res := &KubeconfigResponse{
  1123. Kubeconfig: bytes,
  1124. }
  1125. if err := json.NewEncoder(w).Encode(res); err != nil {
  1126. app.handleErrorFormDecoding(err, ErrK8sDecode, w)
  1127. return
  1128. }
  1129. }
  1130. func (app *App) HandleListNodes(w http.ResponseWriter, r *http.Request) {
  1131. id, err := strconv.ParseUint(chi.URLParam(r, "cluster_id"), 0, 64)
  1132. if err != nil || id == 0 {
  1133. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  1134. return
  1135. }
  1136. cluster, err := app.Repo.Cluster.ReadCluster(uint(id))
  1137. if err != nil {
  1138. app.handleErrorRead(err, ErrProjectDataRead, w)
  1139. return
  1140. }
  1141. form := &forms.K8sForm{
  1142. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  1143. Repo: app.Repo,
  1144. DigitalOceanOAuth: app.DOConf,
  1145. Cluster: cluster,
  1146. },
  1147. }
  1148. var agent *kubernetes.Agent
  1149. if app.ServerConf.IsTesting {
  1150. agent = app.TestAgents.K8sAgent
  1151. } else {
  1152. agent, _ = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  1153. }
  1154. nodeWithUsageList := nodes.GetNodesUsage(agent.Clientset)
  1155. w.WriteHeader(http.StatusOK)
  1156. if err := json.NewEncoder(w).Encode(nodeWithUsageList); err != nil {
  1157. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  1158. return
  1159. }
  1160. }
  1161. func (app *App) HandleGetNode(w http.ResponseWriter, r *http.Request) {
  1162. cluster_id, err := strconv.ParseUint(chi.URLParam(r, "cluster_id"), 0, 64)
  1163. node_name := chi.URLParam(r, "node_name")
  1164. if err != nil || cluster_id == 0 {
  1165. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  1166. return
  1167. }
  1168. cluster, err := app.Repo.Cluster.ReadCluster(uint(cluster_id))
  1169. if err != nil {
  1170. app.handleErrorRead(err, ErrProjectDataRead, w)
  1171. return
  1172. }
  1173. form := &forms.K8sForm{
  1174. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  1175. Repo: app.Repo,
  1176. DigitalOceanOAuth: app.DOConf,
  1177. Cluster: cluster,
  1178. },
  1179. }
  1180. var agent *kubernetes.Agent
  1181. if app.ServerConf.IsTesting {
  1182. agent = app.TestAgents.K8sAgent
  1183. } else {
  1184. agent, _ = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  1185. }
  1186. nodeWithUsageData := nodes.DescribeNode(agent.Clientset, node_name)
  1187. w.WriteHeader(http.StatusOK)
  1188. if err := json.NewEncoder(w).Encode(nodeWithUsageData); err != nil {
  1189. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  1190. return
  1191. }
  1192. }