diff --git a/mgmt/rest/plugin.go b/mgmt/rest/plugin.go index 7d4d0fb4b..6e1bf9d41 100644 --- a/mgmt/rest/plugin.go +++ b/mgmt/rest/plugin.go @@ -259,26 +259,31 @@ func (s *Server) unloadPlugin(w http.ResponseWriter, r *http.Request, p httprout respond(200, pr, w) } -func (s *Server) getPlugins(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { +func (s *Server) getPlugins(w http.ResponseWriter, r *http.Request, params httprouter.Params) { var detail bool - // make this a function because DRY for k := range r.URL.Query() { if k == "details" { detail = true } } + plName := params.ByName("name") + plType := params.ByName("type") + respond(200, getPlugins(s.mm, detail, r.Host, plName, plType), w) +} + +func getPlugins(mm managesMetrics, detail bool, h string, plName string, plType string) *rbody.PluginList { + + plCatalog := mm.PluginCatalog() - plugins := new(rbody.PluginList) + plugins := rbody.PluginList{} - // Cache the catalog here to avoid multiple reads - plCatalog := s.mm.PluginCatalog() plugins.LoadedPlugins = make([]rbody.LoadedPlugin, len(plCatalog)) - for i, p := range s.mm.PluginCatalog() { - plugins.LoadedPlugins[i] = *catalogedPluginToLoaded(r.Host, p) + for i, p := range plCatalog { + plugins.LoadedPlugins[i] = *catalogedPluginToLoaded(h, p) } if detail { - aPlugins := s.mm.AvailablePlugins() + aPlugins := mm.AvailablePlugins() plugins.AvailablePlugins = make([]rbody.AvailablePlugin, len(aPlugins)) for i, p := range aPlugins { plugins.AvailablePlugins[i] = rbody.AvailablePlugin{ @@ -292,7 +297,41 @@ func (s *Server) getPlugins(w http.ResponseWriter, r *http.Request, _ httprouter } } - respond(200, plugins, w) + filteredPlugins := rbody.PluginList{} + + if plName != "" { + for _, p := range plugins.LoadedPlugins { + if p.Name == plName { + filteredPlugins.LoadedPlugins = append(filteredPlugins.LoadedPlugins, p) + } + } + for _, p := range plugins.AvailablePlugins { + if p.Name == plName { + filteredPlugins.AvailablePlugins = append(filteredPlugins.AvailablePlugins, p) + } + } + // update plugins so that further filters consider previous filters + plugins = filteredPlugins + } + + filteredPlugins = rbody.PluginList{} + + if plType != "" { + for _, p := range plugins.LoadedPlugins { + if p.Type == plType { + filteredPlugins.LoadedPlugins = append(filteredPlugins.LoadedPlugins, p) + } + } + for _, p := range plugins.AvailablePlugins { + if p.Type == plType { + filteredPlugins.AvailablePlugins = append(filteredPlugins.AvailablePlugins, p) + } + } + // filter based on type + plugins = filteredPlugins + } + + return &plugins } func catalogedPluginToLoaded(host string, c core.CatalogedPlugin) *rbody.LoadedPlugin { @@ -307,12 +346,6 @@ func catalogedPluginToLoaded(host string, c core.CatalogedPlugin) *rbody.LoadedP } } -func (s *Server) getPluginsByType(w http.ResponseWriter, r *http.Request, params httprouter.Params) { -} - -func (s *Server) getPluginsByName(w http.ResponseWriter, r *http.Request, params httprouter.Params) { -} - func (s *Server) getPlugin(w http.ResponseWriter, r *http.Request, p httprouter.Params) { plName := p.ByName("name") plType := p.ByName("type") diff --git a/mgmt/rest/plugin_test.go b/mgmt/rest/plugin_test.go new file mode 100644 index 000000000..b69b89a5f --- /dev/null +++ b/mgmt/rest/plugin_test.go @@ -0,0 +1,170 @@ +/* +http://www.apache.org/licenses/LICENSE-2.0.txt + + +Copyright 2015 Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package rest + +import ( + "testing" + "time" + + "github.com/intelsdi-x/snap/control/plugin/cpolicy" + "github.com/intelsdi-x/snap/core" + "github.com/intelsdi-x/snap/core/serror" + . "github.com/smartystreets/goconvey/convey" +) + +type MockLoadedPlugin struct { + MyName string + MyType string +} + +func (m MockLoadedPlugin) Name() string { return m.MyName } +func (m MockLoadedPlugin) TypeName() string { return m.MyType } +func (m MockLoadedPlugin) Version() int { return 0 } +func (m MockLoadedPlugin) Plugin() string { return "" } +func (m MockLoadedPlugin) IsSigned() bool { return false } +func (m MockLoadedPlugin) Status() string { return "" } +func (m MockLoadedPlugin) PluginPath() string { return "" } +func (m MockLoadedPlugin) LoadedTimestamp() *time.Time { + now := time.Now() + return &now +} +func (m MockLoadedPlugin) Policy() *cpolicy.ConfigPolicy { return nil } + +// have my mock object also support AvailablePlugin +func (m MockLoadedPlugin) HitCount() int { return 0 } +func (m MockLoadedPlugin) LastHit() time.Time { + return time.Now() +} +func (m MockLoadedPlugin) ID() uint32 { return 0 } + +type MockManagesMetrics struct{} + +func (m MockManagesMetrics) MetricCatalog() ([]core.CatalogedMetric, error) { + return nil, nil +} +func (m MockManagesMetrics) FetchMetrics([]string, int) ([]core.CatalogedMetric, error) { + return nil, nil +} +func (m MockManagesMetrics) GetMetricVersions([]string) ([]core.CatalogedMetric, error) { + return nil, nil +} +func (m MockManagesMetrics) GetMetric([]string, int) (core.CatalogedMetric, error) { + return nil, nil +} +func (m MockManagesMetrics) Load(*core.RequestedPlugin) (core.CatalogedPlugin, serror.SnapError) { + return nil, nil +} +func (m MockManagesMetrics) Unload(core.Plugin) (core.CatalogedPlugin, serror.SnapError) { + return nil, nil +} + +func (m MockManagesMetrics) PluginCatalog() core.PluginCatalog { + return []core.CatalogedPlugin{ + MockLoadedPlugin{MyName: "foo", MyType: "collector"}, + MockLoadedPlugin{MyName: "bar", MyType: "publisher"}, + MockLoadedPlugin{MyName: "foo", MyType: "collector"}, + MockLoadedPlugin{MyName: "baz", MyType: "publisher"}, + MockLoadedPlugin{MyName: "foo", MyType: "processor"}, + MockLoadedPlugin{MyName: "foobar", MyType: "processor"}, + } +} +func (m MockManagesMetrics) AvailablePlugins() []core.AvailablePlugin { + return []core.AvailablePlugin{ + MockLoadedPlugin{MyName: "foo", MyType: "collector"}, + MockLoadedPlugin{MyName: "bar", MyType: "publisher"}, + MockLoadedPlugin{MyName: "foo", MyType: "collector"}, + MockLoadedPlugin{MyName: "baz", MyType: "publisher"}, + MockLoadedPlugin{MyName: "foo", MyType: "processor"}, + MockLoadedPlugin{MyName: "foobar", MyType: "processor"}, + } +} +func (m MockManagesMetrics) GetAutodiscoverPaths() []string { + return nil +} + +func TestGetPlugins(t *testing.T) { + mm := MockManagesMetrics{} + host := "localhost" + Convey("Test getPlugns method", t, func() { + Convey("Without details", func() { + detail := false + Convey("Get All plugins", func() { + plName := "" + plType := "" + plugins := getPlugins(mm, detail, host, plName, plType) + So(len(plugins.LoadedPlugins), ShouldEqual, 6) + So(len(plugins.AvailablePlugins), ShouldEqual, 0) + }) + Convey("Filter plugins by Type", func() { + plName := "" + plType := "publisher" + plugins := getPlugins(mm, detail, host, plName, plType) + So(len(plugins.LoadedPlugins), ShouldEqual, 2) + So(len(plugins.AvailablePlugins), ShouldEqual, 0) + }) + Convey("Filter plugins by Type and Name", func() { + plName := "foo" + plType := "processor" + plugins := getPlugins(mm, detail, host, plName, plType) + So(len(plugins.LoadedPlugins), ShouldEqual, 1) + So(len(plugins.AvailablePlugins), ShouldEqual, 0) + }) + Convey("Filter plugins by Type and Name expect duplicates", func() { + plName := "foo" + plType := "collector" + plugins := getPlugins(mm, detail, host, plName, plType) + So(len(plugins.LoadedPlugins), ShouldEqual, 2) + So(len(plugins.AvailablePlugins), ShouldEqual, 0) + }) + }) + Convey("With details", func() { + detail := true + Convey("Get All plugins", func() { + plName := "" + plType := "" + plugins := getPlugins(mm, detail, host, plName, plType) + So(len(plugins.LoadedPlugins), ShouldEqual, 6) + So(len(plugins.AvailablePlugins), ShouldEqual, 6) + }) + Convey("Filter plugins by Type", func() { + plName := "" + plType := "publisher" + plugins := getPlugins(mm, detail, host, plName, plType) + So(len(plugins.LoadedPlugins), ShouldEqual, 2) + So(len(plugins.AvailablePlugins), ShouldEqual, 2) + }) + Convey("Filter plugins by Type and Name", func() { + plName := "foo" + plType := "processor" + plugins := getPlugins(mm, detail, host, plName, plType) + So(len(plugins.LoadedPlugins), ShouldEqual, 1) + So(len(plugins.AvailablePlugins), ShouldEqual, 1) + }) + Convey("Filter plugins by Type and Name expect duplicates", func() { + plName := "foo" + plType := "collector" + plugins := getPlugins(mm, detail, host, plName, plType) + So(len(plugins.LoadedPlugins), ShouldEqual, 2) + So(len(plugins.AvailablePlugins), ShouldEqual, 2) + }) + }) + }) + +} diff --git a/mgmt/rest/server.go b/mgmt/rest/server.go index 53bff995a..65a92ee54 100644 --- a/mgmt/rest/server.go +++ b/mgmt/rest/server.go @@ -284,8 +284,8 @@ func (s *Server) BindConfigManager(c managesConfig) { func (s *Server) addRoutes() { // plugin routes s.r.GET("/v1/plugins", s.getPlugins) - s.r.GET("/v1/plugins/:type", s.getPluginsByType) - s.r.GET("/v1/plugins/:type/:name", s.getPluginsByName) + s.r.GET("/v1/plugins/:type", s.getPlugins) + s.r.GET("/v1/plugins/:type/:name", s.getPlugins) s.r.GET("/v1/plugins/:type/:name/:version", s.getPlugin) s.r.POST("/v1/plugins", s.loadPlugin) s.r.DELETE("/v1/plugins/:type/:name/:version", s.unloadPlugin)