2
0

tailscale_services.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package addons
  2. import (
  3. "fmt"
  4. "net/http"
  5. "github.com/porter-dev/porter/api/server/authz"
  6. "github.com/porter-dev/porter/api/server/handlers"
  7. "github.com/porter-dev/porter/api/server/shared"
  8. "github.com/porter-dev/porter/api/server/shared/apierrors"
  9. "github.com/porter-dev/porter/api/server/shared/config"
  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. )
  14. // TailscaleServicesHandler handles requests to the /addons/tailscale-services endpoint
  15. type TailscaleServicesHandler struct {
  16. handlers.PorterHandlerReadWriter
  17. authz.KubernetesAgentGetter
  18. }
  19. // NewTailscaleServicesHandler returns a new TailscaleServicesHandler
  20. func NewTailscaleServicesHandler(
  21. config *config.Config,
  22. decoderValidator shared.RequestDecoderValidator,
  23. writer shared.ResultWriter,
  24. ) *TailscaleServicesHandler {
  25. return &TailscaleServicesHandler{
  26. PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
  27. KubernetesAgentGetter: authz.NewOutOfClusterAgentGetter(config),
  28. }
  29. }
  30. // TailscaleServicesResponse represents the response from the /addons/tailscale-services endpoints
  31. type TailscaleServicesResponse struct {
  32. Services []TailscaleService `json:"services"`
  33. }
  34. // TailscaleService represents a Tailscale service
  35. type TailscaleService struct {
  36. Name string `json:"name"`
  37. IP string `json:"ip"`
  38. Port int `json:"port"`
  39. }
  40. // ServeHTTP returns all services that can be accessed through Tailscale
  41. // TODO: move this logic to CCP
  42. func (c *TailscaleServicesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  43. ctx, span := telemetry.NewSpan(r.Context(), "serve-get-tailscale-services")
  44. defer span.End()
  45. project, _ := ctx.Value(types.ProjectScope).(*models.Project)
  46. deploymentTarget, _ := ctx.Value(types.DeploymentTargetScope).(types.DeploymentTarget)
  47. telemetry.WithAttributes(span,
  48. telemetry.AttributeKV{Key: "namespace", Value: deploymentTarget.Namespace},
  49. telemetry.AttributeKV{Key: "cluster-id", Value: deploymentTarget.ClusterID},
  50. )
  51. cluster, err := c.Repo().Cluster().ReadCluster(project.ID, deploymentTarget.ClusterID)
  52. if err != nil {
  53. err = telemetry.Error(ctx, span, err, "error reading cluster")
  54. c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
  55. return
  56. }
  57. agent, err := c.GetAgent(r, cluster, deploymentTarget.Namespace)
  58. if err != nil {
  59. err = telemetry.Error(ctx, span, err, "error getting agent")
  60. c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
  61. return
  62. }
  63. svcList, err := agent.ListServices(ctx, deploymentTarget.Namespace, "porter.run/tailscale-svc=true")
  64. if err != nil {
  65. err = telemetry.Error(ctx, span, err, "error listing services")
  66. c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
  67. return
  68. }
  69. services := make([]TailscaleService, 0)
  70. for _, svc := range svcList.Items {
  71. var port int
  72. if len(svc.Spec.Ports) > 0 {
  73. port = int(svc.Spec.Ports[0].Port)
  74. }
  75. service := TailscaleService{
  76. Name: svc.Name,
  77. IP: svc.Spec.ClusterIP,
  78. Port: port,
  79. }
  80. if appName, ok := svc.Labels["porter.run/app-name"]; ok {
  81. if serviceName, ok := svc.Labels["porter.run/service-name"]; ok {
  82. service.Name = fmt.Sprintf("%s (%s)", serviceName, appName)
  83. }
  84. }
  85. services = append(services, service)
  86. }
  87. resp := TailscaleServicesResponse{
  88. Services: services,
  89. }
  90. c.WriteResult(w, r, resp)
  91. }