diff --git a/lib/service/service.go b/lib/service/service.go index c429a48e62a00..9372b450d381d 100644 --- a/lib/service/service.go +++ b/lib/service/service.go @@ -4008,7 +4008,8 @@ func getPublicAddr(authClient auth.ReadAppsAccessPoint, a App) (string, error) { for { select { case <-ticker.C: - publicAddr, err := findPublicAddr(authClient, a) + publicAddr, err := app.FindPublicAddr(authClient, a.PublicAddr, a.Name) + if err == nil { return publicAddr, nil } @@ -4018,37 +4019,6 @@ func getPublicAddr(authClient auth.ReadAppsAccessPoint, a App) (string, error) { } } -// findPublicAddr tries to resolve the public address of the proxy of this cluster. -func findPublicAddr(authClient auth.ReadAppsAccessPoint, a App) (string, error) { - // If the application has a public address already set, use it. - if a.PublicAddr != "" { - return a.PublicAddr, nil - } - - // Fetch list of proxies, if first has public address set, use it. - servers, err := authClient.GetProxies() - if err != nil { - return "", trace.Wrap(err) - } - if len(servers) == 0 { - return "", trace.BadParameter("cluster has no proxied registered, at least one proxy must be registered for application access") - } - if servers[0].GetPublicAddr() != "" { - addr, err := utils.ParseAddr(servers[0].GetPublicAddr()) - if err != nil { - return "", trace.Wrap(err) - } - return fmt.Sprintf("%v.%v", a.Name, addr.Host()), nil - } - - // Fall back to cluster name. - cn, err := authClient.GetClusterName() - if err != nil { - return "", trace.Wrap(err) - } - return fmt.Sprintf("%v.%v", a.Name, cn.GetClusterName()), nil -} - // newHTTPFileSystem creates a new HTTP file system for the web handler. // It uses external configuration to make the decision func newHTTPFileSystem() (http.FileSystem, error) { diff --git a/lib/srv/app/watcher.go b/lib/srv/app/watcher.go index 52cbb16c7774e..94552cf92be37 100644 --- a/lib/srv/app/watcher.go +++ b/lib/srv/app/watcher.go @@ -18,11 +18,13 @@ package app import ( "context" + "fmt" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/services" - + "github.com/gravitational/teleport/lib/utils" "github.com/gravitational/trace" ) @@ -82,7 +84,11 @@ func (s *Server) startResourceWatcher(ctx context.Context) (*services.AppWatcher for { select { case apps := <-watcher.AppsC: - s.monitoredApps.setResources(apps) + appsWithAddr := make(types.Apps, 0, len(apps)) + for _, app := range apps { + appsWithAddr = append(appsWithAddr, s.guessPublicAddr(app)) + } + s.monitoredApps.setResources(appsWithAddr) select { case s.reconcileCh <- struct{}{}: case <-ctx.Done(): @@ -97,6 +103,52 @@ func (s *Server) startResourceWatcher(ctx context.Context) (*services.AppWatcher return watcher, nil } +// guessPublicAddr will guess PublicAddr for given application if it is missing, based on proxy information and app name. +func (s *Server) guessPublicAddr(app types.Application) types.Application { + if app.GetPublicAddr() != "" { + return app + } + appCopy := app.Copy() + pubAddr, err := FindPublicAddr(s.c.AccessPoint, app.GetPublicAddr(), app.GetName()) + if err == nil { + appCopy.Spec.PublicAddr = pubAddr + } else { + s.log.WithError(err).Errorf("Unable to find public address for app %q, leaving empty.", app.GetName()) + } + return appCopy +} + +// FindPublicAddr tries to resolve the public address of the proxy of this cluster. +func FindPublicAddr(authClient auth.ReadAppsAccessPoint, appPublicAddr string, appName string) (string, error) { + // If the application has a public address already set, use it. + if appPublicAddr != "" { + return appPublicAddr, nil + } + + // Fetch list of proxies, if first has public address set, use it. + servers, err := authClient.GetProxies() + if err != nil { + return "", trace.Wrap(err) + } + if len(servers) == 0 { + return "", trace.BadParameter("cluster has no proxy registered, at least one proxy must be registered for application access") + } + if servers[0].GetPublicAddr() != "" { + addr, err := utils.ParseAddr(servers[0].GetPublicAddr()) + if err != nil { + return "", trace.Wrap(err) + } + return fmt.Sprintf("%v.%v", appName, addr.Host()), nil + } + + // Fall back to cluster name. + cn, err := authClient.GetClusterName() + if err != nil { + return "", trace.Wrap(err) + } + return fmt.Sprintf("%v.%v", appName, cn.GetClusterName()), nil +} + func (s *Server) getResources() (resources types.ResourcesWithLabelsMap) { return s.getApps().AsResources().ToMap() }