detect_agent_installed.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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.DetectAgentResponse{
  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. res.Version = "v" + strings.TrimPrefix(res.Version, "v")
  73. res.LatestVersion = "v" + strings.TrimPrefix(res.LatestVersion, "v")
  74. c.WriteResult(w, r, res)
  75. }
  76. func getAgentVersionFromDeployment(depl *v1.Deployment) string {
  77. versionAnn, ok := depl.ObjectMeta.Annotations["porter.run/agent-version"]
  78. if !ok {
  79. // fallback to porter agent v2 annotation
  80. versionAnn = depl.ObjectMeta.Annotations["porter.run/agent-major-version"]
  81. }
  82. if versionAnn != "" {
  83. return versionAnn
  84. }
  85. return "v1"
  86. }
  87. func getLatestAgentVersion(helmRepoURL string) (string, error) {
  88. chart, err := loader.LoadChartPublic(helmRepoURL, "porter-agent", "")
  89. if err != nil {
  90. return "", fmt.Errorf("could not load latest porter-agent chart: %w", err)
  91. }
  92. return chart.Metadata.Version, nil
  93. }