2
0

agent_handler.go 3.9 KB

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