detect_agent_installed.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. package cluster
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/http"
  6. "strings"
  7. "github.com/Masterminds/semver/v3"
  8. "github.com/porter-dev/porter/api/server/authz"
  9. "github.com/porter-dev/porter/api/server/handlers"
  10. "github.com/porter-dev/porter/api/server/shared"
  11. "github.com/porter-dev/porter/api/server/shared/apierrors"
  12. "github.com/porter-dev/porter/api/server/shared/config"
  13. "github.com/porter-dev/porter/api/types"
  14. "github.com/porter-dev/porter/internal/helm/loader"
  15. "github.com/porter-dev/porter/internal/kubernetes"
  16. "github.com/porter-dev/porter/internal/models"
  17. v1 "k8s.io/api/apps/v1"
  18. )
  19. type DetectAgentInstalledHandler struct {
  20. handlers.PorterHandlerWriter
  21. authz.KubernetesAgentGetter
  22. }
  23. func NewDetectAgentInstalledHandler(
  24. config *config.Config,
  25. writer shared.ResultWriter,
  26. ) *DetectAgentInstalledHandler {
  27. return &DetectAgentInstalledHandler{
  28. PorterHandlerWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
  29. KubernetesAgentGetter: authz.NewOutOfClusterAgentGetter(config),
  30. }
  31. }
  32. func (c *DetectAgentInstalledHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  33. cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
  34. agent, err := c.GetAgent(r, cluster, "")
  35. if err != nil {
  36. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  37. return
  38. }
  39. depl, err := agent.GetPorterAgent()
  40. if targetErr := kubernetes.IsNotFoundError; err != nil && errors.Is(err, targetErr) {
  41. http.NotFound(w, r)
  42. return
  43. } else if err != nil {
  44. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  45. return
  46. }
  47. // detect the version of the agent which is installed
  48. res := &types.GetAgentResponse{
  49. Version: getAgentVersionFromDeployment(depl),
  50. ShouldUpgrade: false,
  51. }
  52. res.LatestVersion, err = getLatestAgentVersion(c.Config().ServerConf.DefaultAddonHelmRepoURL)
  53. if err != nil {
  54. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  55. return
  56. }
  57. if res.LatestVersion != res.Version {
  58. versionSem, err := semver.NewConstraint(fmt.Sprintf("> %s", strings.TrimPrefix(res.Version, "v")))
  59. if err != nil {
  60. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  61. return
  62. }
  63. latestVersionSem, err := semver.NewVersion(strings.TrimPrefix(res.LatestVersion, "v"))
  64. if err != nil {
  65. c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
  66. return
  67. }
  68. if versionSem.Check(latestVersionSem) {
  69. res.ShouldUpgrade = true
  70. }
  71. }
  72. c.WriteResult(w, r, res)
  73. }
  74. func getAgentVersionFromDeployment(depl *v1.Deployment) string {
  75. versionAnn, ok := depl.ObjectMeta.Annotations["porter.run/agent-version"]
  76. if !ok {
  77. // fallback to porter agent v2 annotation
  78. versionAnn = depl.ObjectMeta.Annotations["porter.run/agent-major-version"]
  79. }
  80. if versionAnn != "" {
  81. return versionAnn
  82. }
  83. return "v1"
  84. }
  85. func getLatestAgentVersion(helmRepoURL string) (string, error) {
  86. chart, err := loader.LoadChartPublic(helmRepoURL, "porter-agent", "")
  87. if err != nil {
  88. return "", fmt.Errorf("could not load latest porter-agent chart: %w", err)
  89. }
  90. return chart.Metadata.Version, nil
  91. }