diff --git a/docker/blocks/graphite/Dockerfile b/docker/blocks/graphite/Dockerfile index 0c85798dd8a..aeac91b7a58 100644 --- a/docker/blocks/graphite/Dockerfile +++ b/docker/blocks/graphite/Dockerfile @@ -1,68 +1,50 @@ -from ubuntu:14.10 +from ubuntu:14.04 -run apt-get -y update +run apt-get -y update -run apt-get -y install software-properties-common - -run apt-get -y install python-software-properties &&\ - add-apt-repository ppa:chris-lea/node.js &&\ - apt-get -y update - -run apt-get -y install python-django-tagging python-simplejson python-memcache \ - python-ldap python-cairo python-django python-twisted \ - python-pysqlite2 python-support python-pip gunicorn \ - supervisor nginx-light nodejs git wget curl - -# Install statsd -run mkdir /src && git clone https://github.com/etsy/statsd.git /src/statsd +run apt-get -y install libcairo2-dev libffi-dev pkg-config python-dev python-pip fontconfig apache2 libapache2-mod-wsgi git-core collectd memcached gcc g++ make supervisor nginx-light gunicorn run cd /usr/local/src && git clone https://github.com/graphite-project/graphite-web.git run cd /usr/local/src && git clone https://github.com/graphite-project/carbon.git run cd /usr/local/src && git clone https://github.com/graphite-project/whisper.git run cd /usr/local/src/whisper && git checkout master && python setup.py install -run cd /usr/local/src/carbon && git checkout 0.9.x && python setup.py install -run cd /usr/local/src/graphite-web && git checkout 0.9.x && python check-dependencies.py; python setup.py install - -# statsd -add ./files/statsd_config.js /src/statsd/config.js +run cd /usr/local/src/carbon && git checkout 0.9.x && pip install -r requirements.txt; python setup.py install +run cd /usr/local/src/graphite-web && git checkout 0.9.x && pip install -r requirements.txt; python check-dependencies.py; python setup.py install # Add graphite config -add ./files/initial_data.json /opt/graphite/webapp/graphite/initial_data.json -add ./files/local_settings.py /opt/graphite/webapp/graphite/local_settings.py -add ./files/carbon.conf /opt/graphite/conf/carbon.conf -add ./files/storage-schemas.conf /opt/graphite/conf/storage-schemas.conf -add ./files/storage-aggregation.conf /opt/graphite/conf/storage-aggregation.conf -add ./files/events_views.py /opt/graphite/webapp/graphite/events/views.py +add ./files/initial_data.json /opt/graphite/webapp/graphite/initial_data.json +add ./files/local_settings.py /opt/graphite/webapp/graphite/local_settings.py +add ./files/carbon.conf /opt/graphite/conf/carbon.conf +add ./files/storage-schemas.conf /opt/graphite/conf/storage-schemas.conf +add ./files/storage-aggregation.conf /opt/graphite/conf/storage-aggregation.conf +add ./files/events_views.py /opt/graphite/webapp/graphite/events/views.py -run mkdir -p /opt/graphite/storage/whisper -run touch /opt/graphite/storage/graphite.db /opt/graphite/storage/index -run chown -R www-data /opt/graphite/storage -run chmod 0775 /opt/graphite/storage /opt/graphite/storage/whisper -run chmod 0664 /opt/graphite/storage/graphite.db -run cd /opt/graphite/webapp/graphite && python manage.py syncdb --noinput +run mkdir -p /opt/graphite/storage/whisper +run touch /opt/graphite/storage/graphite.db /opt/graphite/storage/index +run chown -R www-data /opt/graphite/storage +run chmod 0775 /opt/graphite/storage /opt/graphite/storage/whisper +run chmod 0664 /opt/graphite/storage/graphite.db +run cd /opt/graphite/webapp/graphite && python manage.py syncdb --noinput + +add ./files/my_htpasswd /etc/nginx/.htpasswd # Add system service config -add ./files/nginx.conf /etc/nginx/nginx.conf -add ./files/supervisord.conf /etc/supervisor/conf.d/supervisord.conf - +add ./files/nginx.conf /etc/nginx/nginx.conf +add ./files/supervisord.conf /etc/supervisor/conf.d/supervisord.conf +# Nginx +# # graphite -expose 80 +expose 80 # Carbon line receiver port -expose 2003 +expose 2003 # Carbon cache query port -expose 7002 +expose 7002 -# Statsd UDP port -expose 8125/udp -# Statsd Management port -expose 8126 - -VOLUME ["/var/lib/elasticsearch"] VOLUME ["/opt/graphite/storage/whisper"] VOLUME ["/var/lib/log/supervisor"] -cmd ["/usr/bin/supervisord"] +cmd ["/usr/bin/supervisord"] # vim:ts=8:noet: diff --git a/docker/blocks/graphite/fig b/docker/blocks/graphite/fig index 28e7d3c53a2..84da45341e1 100644 --- a/docker/blocks/graphite/fig +++ b/docker/blocks/graphite/fig @@ -1,4 +1,10 @@ graphite: build: blocks/graphite ports: - - "8776:80" + - "8080:80" + - "2003:2003" + volumes: + - /var/docker/gfdev/graphite:/opt/graphite/storage/whisper + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro + diff --git a/docker/blocks/graphite/files/my_htpasswd b/docker/blocks/graphite/files/my_htpasswd new file mode 100644 index 00000000000..52a72d01b4c --- /dev/null +++ b/docker/blocks/graphite/files/my_htpasswd @@ -0,0 +1 @@ +grafana:$apr1$4R/20xhC$8t37jPP5dbcLr48btdkU// diff --git a/docker/blocks/graphite/files/supervisord.conf b/docker/blocks/graphite/files/supervisord.conf index 25ba39c8819..c9812bb16dc 100644 --- a/docker/blocks/graphite/files/supervisord.conf +++ b/docker/blocks/graphite/files/supervisord.conf @@ -24,10 +24,3 @@ stdout_logfile = /var/log/supervisor/%(program_name)s.log stderr_logfile = /var/log/supervisor/%(program_name)s.log autorestart = true -[program:statsd] -;user = www-data -command = /usr/bin/node /src/statsd/stats.js /src/statsd/config.js -stdout_logfile = /var/log/supervisor/%(program_name)s.log -stderr_logfile = /var/log/supervisor/%(program_name)s.log -autorestart = true - diff --git a/pkg/api/api.go b/pkg/api/api.go index ea434ed71da..8bbb64eb1b2 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -215,7 +215,7 @@ func Register(r *macaron.Macaron) { // rendering r.Get("/render/*", reqSignedIn, RenderToPng) - InitApiPluginRoutes(r) + InitAppPluginRoutes(r) r.NotFound(NotFoundHandler) } diff --git a/pkg/api/api_plugin.go b/pkg/api/app_routes.go similarity index 75% rename from pkg/api/api_plugin.go rename to pkg/api/app_routes.go index 751c234bfe8..6ad41f79b53 100644 --- a/pkg/api/api_plugin.go +++ b/pkg/api/app_routes.go @@ -19,10 +19,10 @@ import ( "github.com/grafana/grafana/pkg/util" ) -func InitApiPluginRoutes(r *macaron.Macaron) { - for _, plugin := range plugins.ApiPlugins { - log.Info("Plugin: Adding proxy routes for api plugin") +func InitAppPluginRoutes(r *macaron.Macaron) { + for _, plugin := range plugins.Apps { for _, route := range plugin.Routes { + log.Info("Plugin: Adding proxy route for app plugin") url := util.JoinUrlFragments("/api/plugin-proxy/", route.Path) handlers := make([]macaron.Handler, 0) if route.ReqSignedIn { @@ -38,24 +38,24 @@ func InitApiPluginRoutes(r *macaron.Macaron) { handlers = append(handlers, middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN)) } } - handlers = append(handlers, ApiPlugin(route, plugin.IncludedInAppId)) + handlers = append(handlers, AppPluginRoute(route, plugin.Id)) r.Route(url, route.Method, handlers...) log.Info("Plugin: Adding route %s", url) } } } -func ApiPlugin(route *plugins.ApiPluginRoute, includedInAppId string) macaron.Handler { +func AppPluginRoute(route *plugins.AppPluginRoute, appId string) macaron.Handler { return func(c *middleware.Context) { path := c.Params("*") - proxy := NewApiPluginProxy(c, path, route, includedInAppId) + proxy := NewApiPluginProxy(c, path, route, appId) proxy.Transport = dataProxyTransport proxy.ServeHTTP(c.Resp, c.Req.Request) } } -func NewApiPluginProxy(ctx *middleware.Context, proxyPath string, route *plugins.ApiPluginRoute, includedInAppId string) *httputil.ReverseProxy { +func NewApiPluginProxy(ctx *middleware.Context, proxyPath string, route *plugins.AppPluginRoute, appId string) *httputil.ReverseProxy { targetUrl, _ := url.Parse(route.Url) director := func(req *http.Request) { @@ -87,21 +87,15 @@ func NewApiPluginProxy(ctx *middleware.Context, proxyPath string, route *plugins return } - jsonData := make(map[string]interface{}) + //lookup appSettings + query := m.GetAppSettingByAppIdQuery{OrgId: ctx.OrgId, AppId: appId} - if includedInAppId != "" { - //lookup appSettings - query := m.GetAppSettingByAppIdQuery{OrgId: ctx.OrgId, AppId: includedInAppId} - - if err := bus.Dispatch(&query); err != nil { - ctx.JsonApiErr(500, "failed to get AppSettings of includedAppId.", err) - return - } - - jsonData = query.Result.JsonData + if err := bus.Dispatch(&query); err != nil { + ctx.JsonApiErr(500, "failed to get AppSettings.", err) + return } - err = t.Execute(&contentBuf, jsonData) + err = t.Execute(&contentBuf, query.Result.JsonData) if err != nil { ctx.JsonApiErr(500, fmt.Sprintf("failed to execute header content template for header %s.", header.Name), err) return diff --git a/pkg/plugins/api_plugin.go b/pkg/plugins/api_plugin.go deleted file mode 100644 index efb16e696d8..00000000000 --- a/pkg/plugins/api_plugin.go +++ /dev/null @@ -1,38 +0,0 @@ -package plugins - -import ( - "encoding/json" - - "github.com/grafana/grafana/pkg/models" -) - -type ApiPluginRoute struct { - Path string `json:"path"` - Method string `json:"method"` - ReqSignedIn bool `json:"reqSignedIn"` - ReqGrafanaAdmin bool `json:"reqGrafanaAdmin"` - ReqRole models.RoleType `json:"reqRole"` - Url string `json:"url"` - Headers []ApiPluginHeader `json:"headers"` -} - -type ApiPlugin struct { - PluginBase - Routes []*ApiPluginRoute `json:"routes"` -} - -type ApiPluginHeader struct { - Name string `json:"name"` - Content string `json:"content"` -} - -func (app *ApiPlugin) Load(decoder *json.Decoder, pluginDir string) error { - if err := decoder.Decode(&app); err != nil { - return err - } - - app.PluginDir = pluginDir - - ApiPlugins[app.Id] = app - return nil -} diff --git a/pkg/plugins/app_plugin.go b/pkg/plugins/app_plugin.go index d2291d487ac..547cd91283c 100644 --- a/pkg/plugins/app_plugin.go +++ b/pkg/plugins/app_plugin.go @@ -26,14 +26,30 @@ type AppIncludeInfo struct { type AppPlugin struct { FrontendPluginBase - Css *AppPluginCss `json:"css"` - Pages []AppPluginPage `json:"pages"` - Includes []AppIncludeInfo `json:"-"` + Css *AppPluginCss `json:"css"` + Pages []AppPluginPage `json:"pages"` + Routes []*AppPluginRoute `json:"routes"` + Includes []AppIncludeInfo `json:"-"` Pinned bool `json:"-"` Enabled bool `json:"-"` } +type AppPluginRoute struct { + Path string `json:"path"` + Method string `json:"method"` + ReqSignedIn bool `json:"reqSignedIn"` + ReqGrafanaAdmin bool `json:"reqGrafanaAdmin"` + ReqRole models.RoleType `json:"reqRole"` + Url string `json:"url"` + Headers []AppPluginRouteHeader `json:"headers"` +} + +type AppPluginRouteHeader struct { + Name string `json:"name"` + Content string `json:"content"` +} + func (app *AppPlugin) Load(decoder *json.Decoder, pluginDir string) error { if err := decoder.Decode(&app); err != nil { return err @@ -59,18 +75,6 @@ func (app *AppPlugin) Load(decoder *json.Decoder, pluginDir string) error { } } - // check if we have child apiPlugins - for _, plugin := range ApiPlugins { - if strings.HasPrefix(plugin.PluginDir, app.PluginDir) { - plugin.IncludedInAppId = app.Id - app.Includes = append(app.Includes, AppIncludeInfo{ - Name: plugin.Name, - Id: plugin.Id, - Type: plugin.Type, - }) - } - } - Apps[app.Id] = app return nil } diff --git a/pkg/plugins/models.go b/pkg/plugins/models.go index b302181e840..55ba8f97767 100644 --- a/pkg/plugins/models.go +++ b/pkg/plugins/models.go @@ -45,7 +45,6 @@ type PluginStaticRoute struct { type EnabledPlugins struct { Panels []*PanelPlugin DataSources map[string]*DataSourcePlugin - ApiList []*ApiPlugin Apps []*AppPlugin } @@ -53,7 +52,6 @@ func NewEnabledPlugins() EnabledPlugins { return EnabledPlugins{ Panels: make([]*PanelPlugin, 0), DataSources: make(map[string]*DataSourcePlugin), - ApiList: make([]*ApiPlugin, 0), Apps: make([]*AppPlugin, 0), } } diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index d6d390d93c0..5878a25a2da 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -17,7 +17,6 @@ import ( var ( DataSources map[string]*DataSourcePlugin Panels map[string]*PanelPlugin - ApiPlugins map[string]*ApiPlugin StaticRoutes []*PluginStaticRoute Apps map[string]*AppPlugin PluginTypes map[string]interface{} @@ -30,14 +29,12 @@ type PluginScanner struct { func Init() error { DataSources = make(map[string]*DataSourcePlugin) - ApiPlugins = make(map[string]*ApiPlugin) StaticRoutes = make([]*PluginStaticRoute, 0) Panels = make(map[string]*PanelPlugin) Apps = make(map[string]*AppPlugin) PluginTypes = map[string]interface{}{ "panel": PanelPlugin{}, "datasource": DataSourcePlugin{}, - "api": ApiPlugin{}, "app": AppPlugin{}, } diff --git a/pkg/plugins/queries.go b/pkg/plugins/queries.go index 58e7d865c63..8e628c5024e 100644 --- a/pkg/plugins/queries.go +++ b/pkg/plugins/queries.go @@ -68,11 +68,5 @@ func GetEnabledPlugins(orgId int64) (*EnabledPlugins, error) { } } - for _, api := range ApiPlugins { - if isPluginEnabled(api.IncludedInAppId) { - enabledPlugins.ApiList = append(enabledPlugins.ApiList, api) - } - } - return &enabledPlugins, nil } diff --git a/public/app/plugins/datasource/opentsdb/datasource.js b/public/app/plugins/datasource/opentsdb/datasource.js index b9593c013a1..d7cc354861f 100644 --- a/public/app/plugins/datasource/opentsdb/datasource.js +++ b/public/app/plugins/datasource/opentsdb/datasource.js @@ -272,6 +272,10 @@ function (angular, _, dateMath) { } query.downsample = interval + "-" + target.downsampleAggregator; + + if (target.downsampleFillPolicy !== "none") { + query.downsample += "-" + target.downsampleFillPolicy; + } } query.tags = angular.copy(target.tags); diff --git a/public/app/plugins/datasource/opentsdb/partials/query.editor.html b/public/app/plugins/datasource/opentsdb/partials/query.editor.html index 8a3c0c0f753..fffa7194228 100644 --- a/public/app/plugins/datasource/opentsdb/partials/query.editor.html +++ b/public/app/plugins/datasource/opentsdb/partials/query.editor.html @@ -104,8 +104,20 @@ -
  • - Disable downsampling +
  • + Fill policy + Available since OpenTSDB 2.2 +
  • + +
  • + +
  • + +
  • + Disable downsampling
  • diff --git a/public/app/plugins/datasource/opentsdb/queryCtrl.js b/public/app/plugins/datasource/opentsdb/queryCtrl.js index 8af3af206b6..14d28c310c2 100644 --- a/public/app/plugins/datasource/opentsdb/queryCtrl.js +++ b/public/app/plugins/datasource/opentsdb/queryCtrl.js @@ -13,6 +13,7 @@ function (angular, _, kbn) { $scope.init = function() { $scope.target.errors = validateTarget($scope.target); $scope.aggregators = ['avg', 'sum', 'min', 'max', 'dev', 'zimsum', 'mimmin', 'mimmax']; + $scope.fillPolicies = ['none', 'nan', 'null', 'zero']; if (!$scope.target.aggregator) { $scope.target.aggregator = 'sum'; @@ -22,6 +23,10 @@ function (angular, _, kbn) { $scope.target.downsampleAggregator = 'avg'; } + if (!$scope.target.downsampleFillPolicy) { + $scope.target.downsampleFillPolicy = 'none'; + } + $scope.datasource.getAggregators().then(function(aggs) { $scope.aggregators = aggs; });