| 
									
										
										
										
											2020-08-21 16:41:10 +08:00
										 |  |  | package server | 
					
						
							| 
									
										
										
										
											2016-09-30 14:36:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2020-07-31 15:45:20 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2017-12-01 21:02:05 +08:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2016-09-30 14:36:20 +08:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2017-09-04 16:42:48 +08:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | 	"reflect" | 
					
						
							| 
									
										
										
										
											2017-09-04 16:42:48 +08:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2020-08-21 16:41:10 +08:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2021-08-25 21:11:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | 	"golang.org/x/sync/errgroup" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-07 05:34:23 +08:00
										 |  |  | 	"github.com/prometheus/client_golang/prometheus" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-29 20:27:29 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api" | 
					
						
							| 
									
										
										
										
											2018-10-26 16:40:33 +08:00
										 |  |  | 	_ "github.com/grafana/grafana/pkg/extensions" | 
					
						
							| 
									
										
										
										
											2019-05-13 14:45:54 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/log" | 
					
						
							| 
									
										
										
										
											2020-10-19 22:58:16 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/metrics" | 
					
						
							| 
									
										
										
										
											2023-01-30 16:26:42 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/usagestats/statscollector" | 
					
						
							| 
									
										
										
										
											2019-04-23 16:24:47 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/registry" | 
					
						
							| 
									
										
										
										
											2023-01-30 16:26:42 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/accesscontrol" | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/provisioning" | 
					
						
							| 
									
										
										
										
											2019-04-23 16:24:47 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2016-09-30 14:36:20 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-25 21:11:22 +08:00
										 |  |  | // Options contains parameters for the New function.
 | 
					
						
							|  |  |  | type Options struct { | 
					
						
							| 
									
										
										
										
											2020-08-21 16:41:10 +08:00
										 |  |  | 	HomePath    string | 
					
						
							|  |  |  | 	PidFile     string | 
					
						
							|  |  |  | 	Version     string | 
					
						
							|  |  |  | 	Commit      string | 
					
						
							|  |  |  | 	BuildBranch string | 
					
						
							|  |  |  | 	Listener    net.Listener | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // New returns a new instance of Server.
 | 
					
						
							| 
									
										
										
										
											2021-08-25 21:11:22 +08:00
										 |  |  | func New(opts Options, cfg *setting.Cfg, httpServer *api.HTTPServer, roleRegistry accesscontrol.RoleRegistry, | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | 	provisioningService provisioning.ProvisioningService, backgroundServiceProvider registry.BackgroundServiceRegistry, | 
					
						
							| 
									
										
										
										
											2022-04-28 17:06:49 +08:00
										 |  |  | 	usageStatsProvidersRegistry registry.UsageStatsProvidersRegistry, statsCollectorService *statscollector.Service, | 
					
						
							| 
									
										
										
										
											2023-12-07 05:34:23 +08:00
										 |  |  | 	promReg prometheus.Registerer, | 
					
						
							| 
									
										
										
										
											2021-08-25 21:11:22 +08:00
										 |  |  | ) (*Server, error) { | 
					
						
							| 
									
										
										
										
											2022-04-28 17:06:49 +08:00
										 |  |  | 	statsCollectorService.RegisterProviders(usageStatsProvidersRegistry.GetServices()) | 
					
						
							| 
									
										
										
										
											2023-12-07 05:34:23 +08:00
										 |  |  | 	s, err := newServer(opts, cfg, httpServer, roleRegistry, provisioningService, backgroundServiceProvider, promReg) | 
					
						
							| 
									
										
										
										
											2021-08-25 21:11:22 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 21:12:01 +08:00
										 |  |  | 	if err := s.Init(); err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-07 15:44:06 +08:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-08-25 21:11:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-07 15:44:06 +08:00
										 |  |  | 	return s, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-25 21:11:22 +08:00
										 |  |  | func newServer(opts Options, cfg *setting.Cfg, httpServer *api.HTTPServer, roleRegistry accesscontrol.RoleRegistry, | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | 	provisioningService provisioning.ProvisioningService, backgroundServiceProvider registry.BackgroundServiceRegistry, | 
					
						
							| 
									
										
										
										
											2023-12-07 05:34:23 +08:00
										 |  |  | 	promReg prometheus.Registerer, | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | ) (*Server, error) { | 
					
						
							|  |  |  | 	rootCtx, shutdownFn := context.WithCancel(context.Background()) | 
					
						
							|  |  |  | 	childRoutines, childCtx := errgroup.WithContext(rootCtx) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s := &Server{ | 
					
						
							| 
									
										
										
										
											2023-12-07 05:34:23 +08:00
										 |  |  | 		promReg:             promReg, | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | 		context:             childCtx, | 
					
						
							|  |  |  | 		childRoutines:       childRoutines, | 
					
						
							|  |  |  | 		HTTPServer:          httpServer, | 
					
						
							|  |  |  | 		provisioningService: provisioningService, | 
					
						
							|  |  |  | 		roleRegistry:        roleRegistry, | 
					
						
							|  |  |  | 		shutdownFn:          shutdownFn, | 
					
						
							|  |  |  | 		shutdownFinished:    make(chan struct{}), | 
					
						
							|  |  |  | 		log:                 log.New("server"), | 
					
						
							|  |  |  | 		cfg:                 cfg, | 
					
						
							|  |  |  | 		pidFile:             opts.PidFile, | 
					
						
							|  |  |  | 		version:             opts.Version, | 
					
						
							|  |  |  | 		commit:              opts.Commit, | 
					
						
							|  |  |  | 		buildBranch:         opts.BuildBranch, | 
					
						
							|  |  |  | 		backgroundServices:  backgroundServiceProvider.GetServices(), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return s, nil | 
					
						
							| 
									
										
										
										
											2016-09-30 14:36:20 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-01 20:09:54 +08:00
										 |  |  | // Server is responsible for managing the lifecycle of services. This is the
 | 
					
						
							|  |  |  | // core Server implementation which starts the entire Grafana server. Use
 | 
					
						
							|  |  |  | // ModuleServer to launch specific modules.
 | 
					
						
							| 
									
										
										
										
											2019-10-14 20:18:22 +08:00
										 |  |  | type Server struct { | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | 	context          context.Context | 
					
						
							|  |  |  | 	shutdownFn       context.CancelFunc | 
					
						
							|  |  |  | 	childRoutines    *errgroup.Group | 
					
						
							| 
									
										
										
										
											2021-04-07 15:44:06 +08:00
										 |  |  | 	log              log.Logger | 
					
						
							|  |  |  | 	cfg              *setting.Cfg | 
					
						
							|  |  |  | 	shutdownOnce     sync.Once | 
					
						
							|  |  |  | 	shutdownFinished chan struct{} | 
					
						
							|  |  |  | 	isInitialized    bool | 
					
						
							|  |  |  | 	mtx              sync.Mutex | 
					
						
							| 
									
										
										
										
											2017-02-06 16:40:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | 	pidFile            string | 
					
						
							|  |  |  | 	version            string | 
					
						
							|  |  |  | 	commit             string | 
					
						
							|  |  |  | 	buildBranch        string | 
					
						
							|  |  |  | 	backgroundServices []registry.BackgroundService | 
					
						
							| 
									
										
										
										
											2019-10-14 20:18:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | 	HTTPServer          *api.HTTPServer | 
					
						
							|  |  |  | 	roleRegistry        accesscontrol.RoleRegistry | 
					
						
							|  |  |  | 	provisioningService provisioning.ProvisioningService | 
					
						
							| 
									
										
										
										
											2023-12-07 05:34:23 +08:00
										 |  |  | 	promReg             prometheus.Registerer | 
					
						
							| 
									
										
										
										
											2016-09-30 14:36:20 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 21:12:01 +08:00
										 |  |  | // Init initializes the server and its services.
 | 
					
						
							|  |  |  | func (s *Server) Init() error { | 
					
						
							| 
									
										
										
										
											2020-08-21 16:41:10 +08:00
										 |  |  | 	s.mtx.Lock() | 
					
						
							|  |  |  | 	defer s.mtx.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if s.isInitialized { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	s.isInitialized = true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-25 11:33:18 +08:00
										 |  |  | 	if err := s.writePIDFile(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-07 05:34:23 +08:00
										 |  |  | 	if err := metrics.SetEnvironmentInformation(s.promReg, s.cfg.MetricsGrafanaEnvironmentInfo); err != nil { | 
					
						
							| 
									
										
										
										
											2020-10-19 22:58:16 +08:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-04 16:42:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | 	if err := s.roleRegistry.RegisterFixedRoles(s.context); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-21 16:41:10 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | 	return s.provisioningService.RunInitProvisioners(s.context) | 
					
						
							| 
									
										
										
										
											2023-07-25 02:01:07 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 16:41:10 +08:00
										 |  |  | // Run initializes and starts services. This will block until all services have
 | 
					
						
							|  |  |  | // exited. To initiate shutdown, call the Shutdown method in another goroutine.
 | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | func (s *Server) Run() error { | 
					
						
							| 
									
										
										
										
											2021-04-07 15:44:06 +08:00
										 |  |  | 	defer close(s.shutdownFinished) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-31 21:12:01 +08:00
										 |  |  | 	if err := s.Init(); err != nil { | 
					
						
							| 
									
										
										
										
											2021-04-07 15:44:06 +08:00
										 |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2020-08-21 16:41:10 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | 	services := s.backgroundServices | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Start background services.
 | 
					
						
							|  |  |  | 	for _, svc := range services { | 
					
						
							|  |  |  | 		if registry.IsDisabled(svc) { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		service := svc | 
					
						
							|  |  |  | 		serviceName := reflect.TypeOf(service).String() | 
					
						
							|  |  |  | 		s.childRoutines.Go(func() error { | 
					
						
							|  |  |  | 			select { | 
					
						
							|  |  |  | 			case <-s.context.Done(): | 
					
						
							|  |  |  | 				return s.context.Err() | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			s.log.Debug("Starting background service", "service", serviceName) | 
					
						
							|  |  |  | 			err := service.Run(s.context) | 
					
						
							|  |  |  | 			// Do not return context.Canceled error since errgroup.Group only
 | 
					
						
							|  |  |  | 			// returns the first error to the caller - thus we can miss a more
 | 
					
						
							|  |  |  | 			// interesting error.
 | 
					
						
							|  |  |  | 			if err != nil && !errors.Is(err, context.Canceled) { | 
					
						
							|  |  |  | 				s.log.Error("Stopped background service", "service", serviceName, "reason", err) | 
					
						
							|  |  |  | 				return fmt.Errorf("%s run error: %w", serviceName, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			s.log.Debug("Stopped background service", "service", serviceName, "reason", err) | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2018-04-27 19:41:58 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	s.notifySystemd("READY=1") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	s.log.Debug("Waiting on services...") | 
					
						
							|  |  |  | 	return s.childRoutines.Wait() | 
					
						
							| 
									
										
										
										
											2017-10-10 01:27:06 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-07 15:44:06 +08:00
										 |  |  | // Shutdown initiates Grafana graceful shutdown. This shuts down all
 | 
					
						
							|  |  |  | // running background services. Since Run blocks Shutdown supposed to
 | 
					
						
							|  |  |  | // be run from a separate goroutine.
 | 
					
						
							| 
									
										
										
										
											2021-04-30 16:55:59 +08:00
										 |  |  | func (s *Server) Shutdown(ctx context.Context, reason string) error { | 
					
						
							|  |  |  | 	var err error | 
					
						
							| 
									
										
										
										
											2021-04-07 15:44:06 +08:00
										 |  |  | 	s.shutdownOnce.Do(func() { | 
					
						
							|  |  |  | 		s.log.Info("Shutdown started", "reason", reason) | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | 		// Call cancel func to stop background services.
 | 
					
						
							|  |  |  | 		s.shutdownFn() | 
					
						
							| 
									
										
										
										
											2021-04-30 16:55:59 +08:00
										 |  |  | 		// Wait for server to shut down
 | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-s.shutdownFinished: | 
					
						
							|  |  |  | 			s.log.Debug("Finished waiting for server to shut down") | 
					
						
							|  |  |  | 		case <-ctx.Done(): | 
					
						
							|  |  |  | 			s.log.Warn("Timed out while waiting for server to shut down") | 
					
						
							|  |  |  | 			err = fmt.Errorf("timeout waiting for shutdown") | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-04-07 15:44:06 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2021-04-30 16:55:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return err | 
					
						
							| 
									
										
										
										
											2018-05-02 20:14:42 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-14 20:18:22 +08:00
										 |  |  | // writePIDFile retrieves the current process ID and writes it to file.
 | 
					
						
							| 
									
										
										
										
											2022-12-25 11:33:18 +08:00
										 |  |  | func (s *Server) writePIDFile() error { | 
					
						
							| 
									
										
										
										
											2019-10-14 20:18:22 +08:00
										 |  |  | 	if s.pidFile == "" { | 
					
						
							| 
									
										
										
										
											2022-12-25 11:33:18 +08:00
										 |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2017-09-04 16:42:48 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Ensure the required directory structure exists.
 | 
					
						
							| 
									
										
										
										
											2019-10-14 20:18:22 +08:00
										 |  |  | 	err := os.MkdirAll(filepath.Dir(s.pidFile), 0700) | 
					
						
							| 
									
										
										
										
											2017-09-04 16:42:48 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-14 20:18:22 +08:00
										 |  |  | 		s.log.Error("Failed to verify pid directory", "error", err) | 
					
						
							| 
									
										
										
										
											2022-12-25 11:33:18 +08:00
										 |  |  | 		return fmt.Errorf("failed to verify pid directory: %s", err) | 
					
						
							| 
									
										
										
										
											2017-09-04 16:42:48 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-14 20:18:22 +08:00
										 |  |  | 	// Retrieve the PID and write it to file.
 | 
					
						
							| 
									
										
										
										
											2017-09-04 16:42:48 +08:00
										 |  |  | 	pid := strconv.Itoa(os.Getpid()) | 
					
						
							| 
									
										
										
										
											2022-08-10 21:37:51 +08:00
										 |  |  | 	if err := os.WriteFile(s.pidFile, []byte(pid), 0644); err != nil { | 
					
						
							| 
									
										
										
										
											2019-10-14 20:18:22 +08:00
										 |  |  | 		s.log.Error("Failed to write pidfile", "error", err) | 
					
						
							| 
									
										
										
										
											2022-12-25 11:33:18 +08:00
										 |  |  | 		return fmt.Errorf("failed to write pidfile: %s", err) | 
					
						
							| 
									
										
										
										
											2017-09-04 16:42:48 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-09-04 18:44:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-14 20:18:22 +08:00
										 |  |  | 	s.log.Info("Writing PID file", "path", s.pidFile, "pid", pid) | 
					
						
							| 
									
										
										
										
											2022-12-25 11:33:18 +08:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2017-09-04 16:42:48 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2023-08-03 21:19:01 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // notifySystemd sends state notifications to systemd.
 | 
					
						
							|  |  |  | func (s *Server) notifySystemd(state string) { | 
					
						
							|  |  |  | 	notifySocket := os.Getenv("NOTIFY_SOCKET") | 
					
						
							|  |  |  | 	if notifySocket == "" { | 
					
						
							|  |  |  | 		s.log.Debug( | 
					
						
							|  |  |  | 			"NOTIFY_SOCKET environment variable empty or unset, can't send systemd notification") | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	socketAddr := &net.UnixAddr{ | 
					
						
							|  |  |  | 		Name: notifySocket, | 
					
						
							|  |  |  | 		Net:  "unixgram", | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.log.Warn("Failed to connect to systemd", "err", err, "socket", notifySocket) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if err := conn.Close(); err != nil { | 
					
						
							|  |  |  | 			s.log.Warn("Failed to close connection", "err", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_, err = conn.Write([]byte(state)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		s.log.Warn("Failed to write notification to systemd", "err", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |