release.go 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. package authz
  2. import (
  3. "context"
  4. "fmt"
  5. "net/http"
  6. "strings"
  7. "github.com/porter-dev/porter/api/server/shared/apierrors"
  8. "github.com/porter-dev/porter/api/server/shared/config"
  9. "github.com/porter-dev/porter/api/server/shared/requestutils"
  10. "github.com/porter-dev/porter/api/types"
  11. "github.com/porter-dev/porter/internal/models"
  12. "github.com/porter-dev/porter/internal/telemetry"
  13. "github.com/stefanmcshane/helm/pkg/release"
  14. )
  15. type ReleaseScopedFactory struct {
  16. config *config.Config
  17. }
  18. func NewReleaseScopedFactory(
  19. config *config.Config,
  20. ) *ReleaseScopedFactory {
  21. return &ReleaseScopedFactory{config}
  22. }
  23. func (p *ReleaseScopedFactory) Middleware(next http.Handler) http.Handler {
  24. return &ReleaseScopedMiddleware{next, p.config, NewOutOfClusterAgentGetter(p.config)}
  25. }
  26. type ReleaseScopedMiddleware struct {
  27. next http.Handler
  28. config *config.Config
  29. agentGetter KubernetesAgentGetter
  30. }
  31. func (p *ReleaseScopedMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  32. ctx, span := telemetry.NewSpan(r.Context(), "middleware-release-scope")
  33. defer span.End()
  34. cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)
  35. helmAgent, err := p.agentGetter.GetHelmAgent(ctx, r, cluster, "")
  36. if err != nil {
  37. apierrors.HandleAPIError(p.config.Logger, p.config.Alerter, w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError), true)
  38. return
  39. }
  40. // get the name of the application
  41. reqScopes, _ := ctx.Value(types.RequestScopeCtxKey).(map[types.PermissionScope]*types.RequestAction)
  42. name := reqScopes[types.ReleaseScope].Resource.Name
  43. // get the version for the application
  44. version, _ := requestutils.GetURLParamUint(r, types.URLParamReleaseVersion)
  45. release, err := helmAgent.GetRelease(ctx, name, int(version), false)
  46. if err != nil {
  47. // ugly casing since at the time of this commit Helm doesn't have an errors package.
  48. // so we rely on the Helm error containing "not found"
  49. if strings.Contains(err.Error(), "not found") {
  50. apierrors.HandleAPIError(p.config.Logger, p.config.Alerter, w, r, apierrors.NewErrPassThroughToClient(
  51. fmt.Errorf("release not found"),
  52. http.StatusNotFound,
  53. ), true)
  54. } else {
  55. apierrors.HandleAPIError(p.config.Logger, p.config.Alerter, w, r, apierrors.NewErrInternal(err), true)
  56. }
  57. return
  58. }
  59. ctx = NewReleaseContext(ctx, release)
  60. r = r.Clone(ctx)
  61. p.next.ServeHTTP(w, r)
  62. }
  63. func NewReleaseContext(ctx context.Context, helmRelease *release.Release) context.Context {
  64. return context.WithValue(ctx, types.ReleaseScope, helmRelease)
  65. }