| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- package provisioning
- import (
- "context"
- "path"
- "sync"
- "github.com/grafana/grafana/pkg/infra/log"
- "github.com/grafana/grafana/pkg/util/errutil"
- "github.com/grafana/grafana/pkg/registry"
- "github.com/grafana/grafana/pkg/services/provisioning/dashboards"
- "github.com/grafana/grafana/pkg/services/provisioning/datasources"
- "github.com/grafana/grafana/pkg/services/provisioning/notifiers"
- "github.com/grafana/grafana/pkg/setting"
- )
- type DashboardProvisioner interface {
- Provision() error
- PollChanges(ctx context.Context)
- GetProvisionerResolvedPath(name string) string
- }
- type DashboardProvisionerFactory func(string) (DashboardProvisioner, error)
- func init() {
- registry.RegisterService(NewProvisioningServiceImpl(
- func(path string) (DashboardProvisioner, error) {
- return dashboards.NewDashboardProvisionerImpl(path)
- },
- notifiers.Provision,
- datasources.Provision,
- ))
- }
- func NewProvisioningServiceImpl(
- newDashboardProvisioner DashboardProvisionerFactory,
- provisionNotifiers func(string) error,
- provisionDatasources func(string) error,
- ) *provisioningServiceImpl {
- return &provisioningServiceImpl{
- log: log.New("provisioning"),
- newDashboardProvisioner: newDashboardProvisioner,
- provisionNotifiers: provisionNotifiers,
- provisionDatasources: provisionDatasources,
- }
- }
- type provisioningServiceImpl struct {
- Cfg *setting.Cfg `inject:""`
- log log.Logger
- pollingCtxCancel context.CancelFunc
- newDashboardProvisioner DashboardProvisionerFactory
- dashboardProvisioner DashboardProvisioner
- provisionNotifiers func(string) error
- provisionDatasources func(string) error
- mutex sync.Mutex
- }
- func (ps *provisioningServiceImpl) Init() error {
- err := ps.ProvisionDatasources()
- if err != nil {
- return err
- }
- err = ps.ProvisionNotifications()
- if err != nil {
- return err
- }
- err = ps.ProvisionDashboards()
- if err != nil {
- return err
- }
- return nil
- }
- func (ps *provisioningServiceImpl) Run(ctx context.Context) error {
- for {
- // Wait for unlock. This is tied to new dashboardProvisioner to be instantiated before we start polling.
- ps.mutex.Lock()
- // Using background here because otherwise if root context was canceled the select later on would
- // non-deterministically take one of the route possibly going into one polling loop before exiting.
- pollingContext, cancelFun := context.WithCancel(context.Background())
- ps.pollingCtxCancel = cancelFun
- ps.dashboardProvisioner.PollChanges(pollingContext)
- ps.mutex.Unlock()
- select {
- case <-pollingContext.Done():
- // Polling was canceled.
- continue
- case <-ctx.Done():
- // Root server context was cancelled so cancel polling and leave.
- ps.cancelPolling()
- return ctx.Err()
- }
- }
- }
- func (ps *provisioningServiceImpl) ProvisionDatasources() error {
- datasourcePath := path.Join(ps.Cfg.ProvisioningPath, "datasources")
- err := ps.provisionDatasources(datasourcePath)
- return errutil.Wrap("Datasource provisioning error", err)
- }
- func (ps *provisioningServiceImpl) ProvisionNotifications() error {
- alertNotificationsPath := path.Join(ps.Cfg.ProvisioningPath, "notifiers")
- err := ps.provisionNotifiers(alertNotificationsPath)
- return errutil.Wrap("Alert notification provisioning error", err)
- }
- func (ps *provisioningServiceImpl) ProvisionDashboards() error {
- dashboardPath := path.Join(ps.Cfg.ProvisioningPath, "dashboards")
- dashProvisioner, err := ps.newDashboardProvisioner(dashboardPath)
- if err != nil {
- return errutil.Wrap("Failed to create provisioner", err)
- }
- ps.mutex.Lock()
- defer ps.mutex.Unlock()
- ps.cancelPolling()
- if err := dashProvisioner.Provision(); err != nil {
- // If we fail to provision with the new provisioner, mutex will unlock and the polling we restart with the
- // old provisioner as we did not switch them yet.
- return errutil.Wrap("Failed to provision dashboards", err)
- }
- ps.dashboardProvisioner = dashProvisioner
- return nil
- }
- func (ps *provisioningServiceImpl) GetDashboardProvisionerResolvedPath(name string) string {
- return ps.dashboardProvisioner.GetProvisionerResolvedPath(name)
- }
- func (ps *provisioningServiceImpl) cancelPolling() {
- if ps.pollingCtxCancel != nil {
- ps.log.Debug("Stop polling for dashboard changes")
- ps.pollingCtxCancel()
- }
- ps.pollingCtxCancel = nil
- }
|