agent_handler.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. package api
  2. import (
  3. "net/http"
  4. "net/url"
  5. "strconv"
  6. "github.com/go-chi/chi"
  7. "github.com/porter-dev/porter/internal/auth/token"
  8. "github.com/porter-dev/porter/internal/forms"
  9. "github.com/porter-dev/porter/internal/helm"
  10. "github.com/porter-dev/porter/internal/helm/loader"
  11. "github.com/porter-dev/porter/internal/kubernetes"
  12. )
  13. // HandleDeployAgent deploys the agent in the Porter cluster
  14. func (app *App) HandleDeployAgent(w http.ResponseWriter, r *http.Request) {
  15. projID, err := strconv.ParseUint(chi.URLParam(r, "project_id"), 0, 64)
  16. if err != nil || projID == 0 {
  17. app.handleErrorFormDecoding(err, ErrProjectDecode, w)
  18. return
  19. }
  20. chart, err := loader.LoadChartPublic(
  21. app.ServerConf.DefaultAddonHelmRepoURL,
  22. "porter-agent",
  23. "latest",
  24. )
  25. if err != nil {
  26. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  27. return
  28. }
  29. vals, err := url.ParseQuery(r.URL.RawQuery)
  30. if err != nil {
  31. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  32. return
  33. }
  34. releaseForm := &forms.ReleaseForm{
  35. Form: &helm.Form{
  36. Repo: app.Repo,
  37. DigitalOceanOAuth: app.DOConf,
  38. Storage: "secret",
  39. Namespace: "porter-agent-system",
  40. },
  41. }
  42. releaseForm.PopulateHelmOptionsFromQueryParams(
  43. vals,
  44. app.Repo.Cluster,
  45. )
  46. agent, err := app.getAgentFromReleaseForm(
  47. w,
  48. r,
  49. releaseForm,
  50. )
  51. if err != nil {
  52. app.handleErrorFormDecoding(err, ErrUserDecode, w)
  53. return
  54. }
  55. // create namespace if not exists
  56. _, err = agent.K8sAgent.CreateNamespace("porter-agent-system")
  57. if err != nil {
  58. app.handleErrorFormDecoding(err, ErrUserDecode, w)
  59. return
  60. }
  61. // add api token to values
  62. userID, err := app.getUserIDFromRequest(r)
  63. if err != nil {
  64. app.handleErrorFormDecoding(err, ErrUserDecode, w)
  65. return
  66. }
  67. jwt, _ := token.GetTokenForAPI(userID, uint(projID))
  68. encoded, err := jwt.EncodeToken(&token.TokenGeneratorConf{
  69. TokenSecret: app.ServerConf.TokenGeneratorSecret,
  70. })
  71. if err != nil {
  72. app.handleErrorInternal(err, w)
  73. return
  74. }
  75. porterAgentValues := map[string]interface{}{
  76. "secret": map[string]interface{}{
  77. "token": encoded,
  78. },
  79. "config": map[string]interface{}{
  80. "projectID": projID,
  81. "clusterID": releaseForm.Cluster.ID,
  82. "porterHost": app.ServerConf.ServerURL,
  83. },
  84. }
  85. conf := &helm.InstallChartConfig{
  86. Chart: chart,
  87. Name: "porter-agent",
  88. Namespace: "porter-agent-system",
  89. Cluster: releaseForm.Cluster,
  90. Repo: *app.Repo,
  91. Values: porterAgentValues,
  92. }
  93. _, err = agent.InstallChart(conf, app.DOConf)
  94. if err != nil {
  95. app.sendExternalError(err, http.StatusInternalServerError, HTTPError{
  96. Code: ErrReleaseDeploy,
  97. Errors: []string{"error installing a new chart: " + err.Error()},
  98. }, w)
  99. return
  100. }
  101. w.WriteHeader(http.StatusOK)
  102. }
  103. // HandleDetectPorterAgentInstalled detects if the agent is installed in the cluster
  104. func (app *App) HandleDetectPorterAgentInstalled(w http.ResponseWriter, r *http.Request) {
  105. vals, err := url.ParseQuery(r.URL.RawQuery)
  106. if err != nil {
  107. app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
  108. return
  109. }
  110. // get the filter options
  111. form := &forms.K8sForm{
  112. OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
  113. Repo: app.Repo,
  114. DigitalOceanOAuth: app.DOConf,
  115. },
  116. }
  117. form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
  118. // validate the form
  119. if err := app.validator.Struct(form); err != nil {
  120. app.handleErrorFormValidation(err, ErrK8sValidate, w)
  121. return
  122. }
  123. // create a new agent
  124. var agent *kubernetes.Agent
  125. if app.ServerConf.IsTesting {
  126. agent = app.TestAgents.K8sAgent
  127. } else {
  128. agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
  129. }
  130. // detect prometheus service
  131. porterAgent, err := agent.GetPorterAgent()
  132. if err != nil || porterAgent == nil {
  133. http.NotFound(w, r)
  134. return
  135. }
  136. w.WriteHeader(http.StatusOK)
  137. return
  138. }