plugins.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. package plugins
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "os"
  6. "path"
  7. "path/filepath"
  8. "strings"
  9. "github.com/grafana/grafana/pkg/log"
  10. "github.com/grafana/grafana/pkg/models"
  11. "github.com/grafana/grafana/pkg/setting"
  12. )
  13. var (
  14. DataSources map[string]*DataSourcePlugin
  15. Panels map[string]*PanelPlugin
  16. ApiPlugins map[string]*ApiPlugin
  17. StaticRoutes []*StaticRootConfig
  18. Apps map[string]*AppPlugin
  19. )
  20. type PluginScanner struct {
  21. pluginPath string
  22. errors []error
  23. }
  24. func Init() error {
  25. DataSources = make(map[string]*DataSourcePlugin)
  26. ApiPlugins = make(map[string]*ApiPlugin)
  27. StaticRoutes = make([]*StaticRootConfig, 0)
  28. Panels = make(map[string]*PanelPlugin)
  29. Apps = make(map[string]*AppPlugin)
  30. scan(path.Join(setting.StaticRootPath, "app/plugins"))
  31. checkPluginPaths()
  32. checkDependencies()
  33. return nil
  34. }
  35. func checkDependencies() {
  36. for appType, app := range Apps {
  37. for _, reqPanel := range app.PanelPlugins {
  38. if _, ok := Panels[reqPanel]; !ok {
  39. log.Fatal(4, "App %s requires Panel type %s, but it is not present.", appType, reqPanel)
  40. }
  41. }
  42. for _, reqDataSource := range app.DatasourcePlugins {
  43. if _, ok := DataSources[reqDataSource]; !ok {
  44. log.Fatal(4, "App %s requires DataSource type %s, but it is not present.", appType, reqDataSource)
  45. }
  46. }
  47. for _, reqApiPlugin := range app.ApiPlugins {
  48. if _, ok := ApiPlugins[reqApiPlugin]; !ok {
  49. log.Fatal(4, "App %s requires ApiPlugin type %s, but it is not present.", appType, reqApiPlugin)
  50. }
  51. }
  52. }
  53. }
  54. func checkPluginPaths() error {
  55. for _, section := range setting.Cfg.Sections() {
  56. if strings.HasPrefix(section.Name(), "plugin.") {
  57. path := section.Key("path").String()
  58. if path != "" {
  59. log.Info("Plugin: Scaning dir %s", path)
  60. scan(path)
  61. }
  62. }
  63. }
  64. return nil
  65. }
  66. func scan(pluginDir string) error {
  67. scanner := &PluginScanner{
  68. pluginPath: pluginDir,
  69. }
  70. if err := filepath.Walk(pluginDir, scanner.walker); err != nil {
  71. return err
  72. }
  73. if len(scanner.errors) > 0 {
  74. return errors.New("Some plugins failed to load")
  75. }
  76. return nil
  77. }
  78. func (scanner *PluginScanner) walker(currentPath string, f os.FileInfo, err error) error {
  79. if err != nil {
  80. return err
  81. }
  82. if f.IsDir() {
  83. return nil
  84. }
  85. if f.Name() == "plugin.json" {
  86. err := scanner.loadPluginJson(currentPath)
  87. if err != nil {
  88. log.Error(3, "Failed to load plugin json file: %v, err: %v", currentPath, err)
  89. scanner.errors = append(scanner.errors, err)
  90. }
  91. }
  92. return nil
  93. }
  94. func addStaticRoot(staticRootConfig *StaticRootConfig, currentDir string) {
  95. if staticRootConfig != nil {
  96. staticRootConfig.Path = path.Join(currentDir, staticRootConfig.Path)
  97. StaticRoutes = append(StaticRoutes, staticRootConfig)
  98. }
  99. }
  100. func (scanner *PluginScanner) loadPluginJson(pluginJsonFilePath string) error {
  101. currentDir := filepath.Dir(pluginJsonFilePath)
  102. reader, err := os.Open(pluginJsonFilePath)
  103. if err != nil {
  104. return err
  105. }
  106. defer reader.Close()
  107. jsonParser := json.NewDecoder(reader)
  108. pluginJson := make(map[string]interface{})
  109. if err := jsonParser.Decode(&pluginJson); err != nil {
  110. return err
  111. }
  112. pluginType, exists := pluginJson["pluginType"]
  113. if !exists {
  114. return errors.New("Did not find pluginType property in plugin.json")
  115. }
  116. if pluginType == "datasource" {
  117. p := DataSourcePlugin{}
  118. reader.Seek(0, 0)
  119. if err := jsonParser.Decode(&p); err != nil {
  120. return err
  121. }
  122. if p.Type == "" {
  123. return errors.New("Did not find type property in plugin.json")
  124. }
  125. DataSources[p.Type] = &p
  126. addStaticRoot(p.StaticRootConfig, currentDir)
  127. }
  128. if pluginType == "panel" {
  129. p := PanelPlugin{}
  130. reader.Seek(0, 0)
  131. if err := jsonParser.Decode(&p); err != nil {
  132. return err
  133. }
  134. if p.Type == "" {
  135. return errors.New("Did not find type property in plugin.json")
  136. }
  137. Panels[p.Type] = &p
  138. addStaticRoot(p.StaticRootConfig, currentDir)
  139. }
  140. if pluginType == "api" {
  141. p := ApiPlugin{}
  142. reader.Seek(0, 0)
  143. if err := jsonParser.Decode(&p); err != nil {
  144. return err
  145. }
  146. if p.Type == "" {
  147. return errors.New("Did not find type property in plugin.json")
  148. }
  149. ApiPlugins[p.Type] = &p
  150. }
  151. if pluginType == "app" {
  152. p := AppPlugin{}
  153. reader.Seek(0, 0)
  154. if err := jsonParser.Decode(&p); err != nil {
  155. return err
  156. }
  157. if p.Type == "" {
  158. return errors.New("Did not find type property in plugin.json")
  159. }
  160. Apps[p.Type] = &p
  161. addStaticRoot(p.StaticRootConfig, currentDir)
  162. }
  163. return nil
  164. }
  165. func GetEnabledPlugins(orgApps []*models.AppPlugin) EnabledPlugins {
  166. enabledPlugins := NewEnabledPlugins()
  167. orgAppsMap := make(map[string]*models.AppPlugin)
  168. for _, orgApp := range orgApps {
  169. orgAppsMap[orgApp.Type] = orgApp
  170. }
  171. seenPanels := make(map[string]bool)
  172. seenApi := make(map[string]bool)
  173. for appType, app := range Apps {
  174. // start with enabled set to the default state listed in the json config.
  175. enabled := app.Enabled
  176. // check if the app is stored in the DB for this org and if so, use the
  177. // enabled state stored there.
  178. if b, ok := orgAppsMap[appType]; ok {
  179. enabled = b.Enabled
  180. }
  181. if enabled {
  182. for _, d := range app.DatasourcePlugins {
  183. if ds, ok := DataSources[d]; ok {
  184. enabledPlugins.DataSourcePlugins[d] = ds
  185. }
  186. }
  187. for _, p := range app.PanelPlugins {
  188. if panel, ok := Panels[p]; ok {
  189. if _, ok := seenPanels[p]; !ok {
  190. seenPanels[p] = true
  191. enabledPlugins.PanelPlugins = append(enabledPlugins.PanelPlugins, panel)
  192. }
  193. }
  194. }
  195. for _, a := range app.ApiPlugins {
  196. if api, ok := ApiPlugins[a]; ok {
  197. if _, ok := seenApi[a]; !ok {
  198. seenApi[a] = true
  199. enabledPlugins.ApiPlugins = append(enabledPlugins.ApiPlugins, api)
  200. }
  201. }
  202. }
  203. enabledPlugins.AppPlugins = append(enabledPlugins.AppPlugins, app)
  204. }
  205. }
  206. // add all plugins that are not part of an App.
  207. for d, installedDs := range DataSources {
  208. if installedDs.App == "" {
  209. enabledPlugins.DataSourcePlugins[d] = installedDs
  210. }
  211. }
  212. for p, panel := range Panels {
  213. if panel.App == "" {
  214. if _, ok := seenPanels[p]; !ok {
  215. seenPanels[p] = true
  216. enabledPlugins.PanelPlugins = append(enabledPlugins.PanelPlugins, panel)
  217. }
  218. }
  219. }
  220. for a, api := range ApiPlugins {
  221. if api.App == "" {
  222. if _, ok := seenApi[a]; !ok {
  223. seenApi[a] = true
  224. enabledPlugins.ApiPlugins = append(enabledPlugins.ApiPlugins, api)
  225. }
  226. }
  227. }
  228. return enabledPlugins
  229. }