2017-10-23 02:02:55 -05:00
|
|
|
package provisioning
|
|
|
|
|
|
|
|
import (
|
2017-11-23 04:29:06 -06:00
|
|
|
"context"
|
2017-12-07 08:14:57 -06:00
|
|
|
"path"
|
2019-04-25 02:06:44 -05:00
|
|
|
"sync"
|
2017-11-23 04:29:06 -06:00
|
|
|
|
2019-05-13 01:45:54 -05:00
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
2018-05-01 08:51:15 -05:00
|
|
|
"github.com/grafana/grafana/pkg/registry"
|
2017-11-30 10:43:28 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/provisioning/dashboards"
|
|
|
|
"github.com/grafana/grafana/pkg/services/provisioning/datasources"
|
2019-01-28 14:04:08 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/provisioning/notifiers"
|
2020-06-22 10:49:13 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/provisioning/plugins"
|
2018-05-01 08:51:15 -05:00
|
|
|
"github.com/grafana/grafana/pkg/setting"
|
2020-06-22 10:49:13 -05:00
|
|
|
"github.com/grafana/grafana/pkg/util/errutil"
|
2017-10-23 02:02:55 -05:00
|
|
|
)
|
|
|
|
|
2020-03-25 08:14:24 -05:00
|
|
|
type ProvisioningService interface {
|
|
|
|
ProvisionDatasources() error
|
2020-06-22 10:49:13 -05:00
|
|
|
ProvisionPlugins() error
|
2020-03-25 08:14:24 -05:00
|
|
|
ProvisionNotifications() error
|
|
|
|
ProvisionDashboards() error
|
|
|
|
GetDashboardProvisionerResolvedPath(name string) string
|
2020-04-15 01:12:52 -05:00
|
|
|
GetAllowUIUpdatesFromConfig(name string) bool
|
2019-04-30 06:32:18 -05:00
|
|
|
}
|
|
|
|
|
2018-05-01 08:51:15 -05:00
|
|
|
func init() {
|
2020-07-16 03:36:08 -05:00
|
|
|
registry.Register(®istry.Descriptor{
|
|
|
|
Name: "ProvisioningService",
|
|
|
|
Instance: NewProvisioningServiceImpl(
|
|
|
|
func(path string) (dashboards.DashboardProvisioner, error) {
|
|
|
|
return dashboards.New(path)
|
|
|
|
},
|
|
|
|
notifiers.Provision,
|
|
|
|
datasources.Provision,
|
|
|
|
plugins.Provision,
|
|
|
|
),
|
|
|
|
InitPriority: registry.Low,
|
|
|
|
})
|
2018-05-01 08:51:15 -05:00
|
|
|
}
|
|
|
|
|
2019-04-25 02:06:44 -05:00
|
|
|
func NewProvisioningServiceImpl(
|
2020-03-25 08:14:24 -05:00
|
|
|
newDashboardProvisioner dashboards.DashboardProvisionerFactory,
|
2019-04-25 02:06:44 -05:00
|
|
|
provisionNotifiers func(string) error,
|
|
|
|
provisionDatasources func(string) error,
|
2020-06-22 10:49:13 -05:00
|
|
|
provisionPlugins func(string) error,
|
2019-04-25 02:06:44 -05:00
|
|
|
) *provisioningServiceImpl {
|
|
|
|
return &provisioningServiceImpl{
|
|
|
|
log: log.New("provisioning"),
|
|
|
|
newDashboardProvisioner: newDashboardProvisioner,
|
|
|
|
provisionNotifiers: provisionNotifiers,
|
|
|
|
provisionDatasources: provisionDatasources,
|
2020-06-22 10:49:13 -05:00
|
|
|
provisionPlugins: provisionPlugins,
|
2017-11-23 04:29:06 -06:00
|
|
|
}
|
2019-04-25 02:06:44 -05:00
|
|
|
}
|
2017-11-23 04:29:06 -06:00
|
|
|
|
2019-04-25 02:06:44 -05:00
|
|
|
type provisioningServiceImpl struct {
|
|
|
|
Cfg *setting.Cfg `inject:""`
|
|
|
|
log log.Logger
|
|
|
|
pollingCtxCancel context.CancelFunc
|
2020-03-25 08:14:24 -05:00
|
|
|
newDashboardProvisioner dashboards.DashboardProvisionerFactory
|
|
|
|
dashboardProvisioner dashboards.DashboardProvisioner
|
2019-04-25 02:06:44 -05:00
|
|
|
provisionNotifiers func(string) error
|
|
|
|
provisionDatasources func(string) error
|
2020-06-22 10:49:13 -05:00
|
|
|
provisionPlugins func(string) error
|
2019-04-25 02:06:44 -05:00
|
|
|
mutex sync.Mutex
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ps *provisioningServiceImpl) Init() error {
|
|
|
|
err := ps.ProvisionDatasources()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-06-22 10:49:13 -05:00
|
|
|
err = ps.ProvisionPlugins()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-04-25 02:06:44 -05:00
|
|
|
err = ps.ProvisionNotifications()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-05-01 08:51:15 -05:00
|
|
|
return nil
|
2017-11-23 04:29:06 -06:00
|
|
|
}
|
|
|
|
|
2019-04-25 02:06:44 -05:00
|
|
|
func (ps *provisioningServiceImpl) Run(ctx context.Context) error {
|
2020-01-17 06:39:41 -06:00
|
|
|
err := ps.ProvisionDashboards()
|
|
|
|
if err != nil {
|
|
|
|
ps.log.Error("Failed to provision dashboard", "error", err)
|
2020-04-14 13:54:00 -05:00
|
|
|
return err
|
2020-01-17 06:39:41 -06:00
|
|
|
}
|
|
|
|
|
2019-04-25 02:06:44 -05:00
|
|
|
for {
|
|
|
|
// Wait for unlock. This is tied to new dashboardProvisioner to be instantiated before we start polling.
|
|
|
|
ps.mutex.Lock()
|
2019-04-30 03:35:54 -05:00
|
|
|
// 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())
|
2019-04-25 02:06:44 -05:00
|
|
|
ps.pollingCtxCancel = cancelFun
|
|
|
|
ps.dashboardProvisioner.PollChanges(pollingContext)
|
|
|
|
ps.mutex.Unlock()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-pollingContext.Done():
|
|
|
|
// Polling was canceled.
|
|
|
|
continue
|
|
|
|
case <-ctx.Done():
|
2019-04-30 03:35:54 -05:00
|
|
|
// Root server context was cancelled so cancel polling and leave.
|
|
|
|
ps.cancelPolling()
|
2019-04-25 02:06:44 -05:00
|
|
|
return ctx.Err()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ps *provisioningServiceImpl) ProvisionDatasources() error {
|
|
|
|
datasourcePath := path.Join(ps.Cfg.ProvisioningPath, "datasources")
|
|
|
|
err := ps.provisionDatasources(datasourcePath)
|
2019-05-15 05:20:17 -05:00
|
|
|
return errutil.Wrap("Datasource provisioning error", err)
|
2019-04-25 02:06:44 -05:00
|
|
|
}
|
|
|
|
|
2020-06-22 10:49:13 -05:00
|
|
|
func (ps *provisioningServiceImpl) ProvisionPlugins() error {
|
|
|
|
appPath := path.Join(ps.Cfg.ProvisioningPath, "plugins")
|
|
|
|
err := ps.provisionPlugins(appPath)
|
|
|
|
return errutil.Wrap("app provisioning error", err)
|
|
|
|
}
|
|
|
|
|
2019-04-25 02:06:44 -05:00
|
|
|
func (ps *provisioningServiceImpl) ProvisionNotifications() error {
|
|
|
|
alertNotificationsPath := path.Join(ps.Cfg.ProvisioningPath, "notifiers")
|
|
|
|
err := ps.provisionNotifiers(alertNotificationsPath)
|
2019-05-15 05:20:17 -05:00
|
|
|
return errutil.Wrap("Alert notification provisioning error", err)
|
2019-04-25 02:06:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ps *provisioningServiceImpl) ProvisionDashboards() error {
|
2018-05-01 08:51:15 -05:00
|
|
|
dashboardPath := path.Join(ps.Cfg.ProvisioningPath, "dashboards")
|
2019-04-25 02:06:44 -05:00
|
|
|
dashProvisioner, err := ps.newDashboardProvisioner(dashboardPath)
|
|
|
|
if err != nil {
|
2019-05-15 05:20:17 -05:00
|
|
|
return errutil.Wrap("Failed to create provisioner", err)
|
2019-04-25 02:06:44 -05:00
|
|
|
}
|
2018-05-01 08:51:15 -05:00
|
|
|
|
2019-04-25 02:06:44 -05:00
|
|
|
ps.mutex.Lock()
|
|
|
|
defer ps.mutex.Unlock()
|
|
|
|
|
|
|
|
ps.cancelPolling()
|
2020-09-11 02:19:44 -05:00
|
|
|
dashProvisioner.CleanUpOrphanedDashboards()
|
2019-04-25 02:06:44 -05:00
|
|
|
|
2020-09-11 02:19:44 -05:00
|
|
|
err = dashProvisioner.Provision()
|
|
|
|
if err != nil {
|
|
|
|
// If we fail to provision with the new provisioner, the mutex will unlock and the polling will restart with the
|
2019-04-25 02:06:44 -05:00
|
|
|
// old provisioner as we did not switch them yet.
|
2019-05-15 05:20:17 -05:00
|
|
|
return errutil.Wrap("Failed to provision dashboards", err)
|
2017-11-23 04:29:06 -06:00
|
|
|
}
|
2019-04-25 02:06:44 -05:00
|
|
|
ps.dashboardProvisioner = dashProvisioner
|
|
|
|
return nil
|
|
|
|
}
|
2018-05-01 08:51:15 -05:00
|
|
|
|
2019-04-30 06:32:18 -05:00
|
|
|
func (ps *provisioningServiceImpl) GetDashboardProvisionerResolvedPath(name string) string {
|
|
|
|
return ps.dashboardProvisioner.GetProvisionerResolvedPath(name)
|
|
|
|
}
|
|
|
|
|
2020-04-15 01:12:52 -05:00
|
|
|
func (ps *provisioningServiceImpl) GetAllowUIUpdatesFromConfig(name string) bool {
|
|
|
|
return ps.dashboardProvisioner.GetAllowUIUpdatesFromConfig(name)
|
2019-10-31 08:27:31 -05:00
|
|
|
}
|
|
|
|
|
2019-04-25 02:06:44 -05:00
|
|
|
func (ps *provisioningServiceImpl) cancelPolling() {
|
|
|
|
if ps.pollingCtxCancel != nil {
|
|
|
|
ps.log.Debug("Stop polling for dashboard changes")
|
|
|
|
ps.pollingCtxCancel()
|
|
|
|
}
|
|
|
|
ps.pollingCtxCancel = nil
|
2017-10-23 02:02:55 -05:00
|
|
|
}
|