Skip to content

Commit

Permalink
Fixes intelsdi-x#385: Added swap plugins to snapctl
Browse files Browse the repository at this point in the history
  • Loading branch information
tiffanyfay committed Mar 24, 2016
1 parent 383a089 commit e9abb1d
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 0 deletions.
11 changes: 11 additions & 0 deletions cmd/snapctl/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ var (
flPluginVersion,
},
},
{
Name: "swap",
Usage: "swap <load_plugin_path> <unload_plugin_type>:<unload_plugin_name>:<unload_plugin_version> or unload -t <unload_plugin_type> -n <unload_plugin_version> -v <unload_plugin_version>",
Action: swapPlugins,
Flags: []cli.Flag{
flPluginAsc,
flPluginType,
flPluginName,
flPluginVersion,
},
},
{
Name: "list",
Usage: "list",
Expand Down
78 changes: 78 additions & 0 deletions cmd/snapctl/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,84 @@ func unloadPlugin(ctx *cli.Context) {
fmt.Printf("Type: %s\n", r.Type)
}

func swapPlugins(ctx *cli.Context) {
// plugin to load
pAsc := ctx.String("plugin-asc")
var paths []string
if len(ctx.Args()) < 1 || len(ctx.Args()) > 2 {
fmt.Println("Incorrect usage:")
cli.ShowCommandHelp(ctx, ctx.Command.Name)
os.Exit(1)
}
paths = append(paths, ctx.Args().First())
if pAsc != "" {
if !strings.Contains(pAsc, ".asc") {
fmt.Println("Must be a .asc file for the -a flag")
cli.ShowCommandHelp(ctx, ctx.Command.Name)
os.Exit(1)
}
paths = append(paths, pAsc)
}

// plugin to unload
var pDetails []string
var pType string
var pName string
var pVer int
var err error

if len(ctx.Args()) == 2 {
pDetails = filepath.SplitList(ctx.Args()[1])
if len(pDetails) == 3 {
pType = pDetails[0]
pName = pDetails[1]
pVer, err = strconv.Atoi(pDetails[2])
if err != nil {
fmt.Println("Can't convert version string to integer")
cli.ShowCommandHelp(ctx, ctx.Command.Name)
os.Exit(1)
}
}
} else {
pType = ctx.String("plugin-type")
pName = ctx.String("plugin-name")
pVer = ctx.Int("plugin-version")
}
if pType == "" {
fmt.Println("Must provide plugin type")
cli.ShowCommandHelp(ctx, ctx.Command.Name)
os.Exit(1)
}
if pName == "" {
fmt.Println("Must provide plugin name")
cli.ShowCommandHelp(ctx, ctx.Command.Name)
os.Exit(1)
}
if pVer < 1 {
fmt.Println("Must provide plugin version")
cli.ShowCommandHelp(ctx, ctx.Command.Name)
os.Exit(1)
}

r := pClient.SwapPlugin(paths, pType, pName, pVer)
if r.Err != nil {
fmt.Printf("Error swapping plugins:\n%v\n", r.Err.Error())
os.Exit(1)
}

fmt.Println("Plugin loaded")
fmt.Printf("Name: %s\n", r.LoadedPlugin.Name)
fmt.Printf("Version: %d\n", r.LoadedPlugin.Version)
fmt.Printf("Type: %s\n", r.LoadedPlugin.Type)
fmt.Printf("Signed: %v\n", r.LoadedPlugin.Signed)
fmt.Printf("Loaded Time: %s\n\n", r.LoadedPlugin.LoadedTime().Format(timeFormat))

fmt.Println("\nPlugin unloaded")
fmt.Printf("Name: %s\n", r.UnloadedPlugin.Name)
fmt.Printf("Version: %d\n", r.UnloadedPlugin.Version)
fmt.Printf("Type: %s\n", r.UnloadedPlugin.Type)
}

func listPlugins(ctx *cli.Context) {
plugins := pClient.GetPlugins(ctx.Bool("running"))
if plugins.Err != nil {
Expand Down
36 changes: 36 additions & 0 deletions mgmt/rest/client/client_func_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,42 @@ func TestSnapClient(t *testing.T) {
})
})

Convey("SwapPlugins", t, func() {
Convey("Swap with different types should fail", func() {
sp := c.SwapPlugin(FILE_PLUGIN_PATH, p1.LoadedPlugins[0].Type, p1.LoadedPlugins[0].Name, p1.LoadedPlugins[0].Version)
So(sp.Err, ShouldNotBeNil)
lps := c.GetPlugins(false)
So(len(lps.LoadedPlugins), ShouldEqual, 1)
})
Convey("Swap with same plugin should fail", func() {
sp := c.SwapPlugin(MOCK_PLUGIN_PATH1, p1.LoadedPlugins[0].Type, p1.LoadedPlugins[0].Name, p1.LoadedPlugins[0].Version)
So(sp.Err, ShouldNotBeNil)
lps := c.GetPlugins(false)
So(len(lps.LoadedPlugins), ShouldEqual, 1)
})
Convey("Swap with plugins with the same type and name", func() {
sp := c.SwapPlugin(MOCK_PLUGIN_PATH2, p1.LoadedPlugins[0].Type, p1.LoadedPlugins[0].Name, p1.LoadedPlugins[0].Version)
So(sp.Err, ShouldBeNil)
lps := c.GetPlugins(false)
So(len(lps.LoadedPlugins), ShouldEqual, 1)
So(lps.LoadedPlugins[0].Type, ShouldEqual, "collector")
So(lps.LoadedPlugins[0].Name, ShouldEqual, "mock")
So(lps.LoadedPlugins[0].Type, ShouldEqual, p1.LoadedPlugins[0].Type)
So(lps.LoadedPlugins[0].Name, ShouldEqual, p1.LoadedPlugins[0].Name)
So(lps.LoadedPlugins[0].Version, ShouldNotEqual, p1.LoadedPlugins[0].Version)

sp2 := c.SwapPlugin(MOCK_PLUGIN_PATH1, sp.LoadedPlugin.Type, sp.LoadedPlugin.Name, sp.LoadedPlugin.Version)
So(sp2.Err, ShouldBeNil)
lps2 := c.GetPlugins(false)
So(len(lps.LoadedPlugins), ShouldEqual, 1)
So(lps2.LoadedPlugins[0].Type, ShouldEqual, "collector")
So(lps2.LoadedPlugins[0].Name, ShouldEqual, "mock")
So(lps2.LoadedPlugins[0].Type, ShouldEqual, sp.LoadedPlugin.Type)
So(lps2.LoadedPlugins[0].Name, ShouldEqual, sp.LoadedPlugin.Name)
So(lps2.LoadedPlugins[0].Version, ShouldNotEqual, sp.LoadedPlugin.Version)
})
})

if cerr == nil {
p2 = c.LoadPlugin(MOCK_PLUGIN_PATH2)
}
Expand Down
52 changes: 52 additions & 0 deletions mgmt/rest/client/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ limitations under the License.
package client

import (
"errors"
"fmt"
"net/url"
"time"
Expand Down Expand Up @@ -78,6 +79,51 @@ func (c *Client) UnloadPlugin(pluginType, name string, version int) *UnloadPlugi
return r
}

// SwapPlugin swaps two plugins with the same type and name e.g. collector:mock:1 with collector:mock:2
func (c *Client) SwapPlugin(loadPath []string, unloadType, unloadName string, unloadVersion int) *SwapPluginsResult {
r := &SwapPluginsResult{}

if len(loadPath) != 1 {
r.Err = errors.New("Did not receive only one plugin to load.")
return r
}
// Load plugin
lp := c.LoadPlugin(loadPath)
if lp.Err != nil {
r.Err = errors.New(lp.Err.Error())
return r
}
if len(lp.LoadedPlugins) != 1 {
r.Err = errors.New("There is not just one plugin to be loaded")
}
lpr := lp.LoadedPlugins[0].LoadedPlugin

// Make sure both plugins have the same type and name before unloading. If not, rollback.
if lpr.Type != unloadType || lpr.Name != unloadName {
up := c.UnloadPlugin(lpr.Type, lpr.Name, lpr.Version)
if up.Err != nil {
r.Err = errors.New("Plugins do not have the same type and name. Failed to rollback after error.")
return r
}
r.Err = errors.New("Plugins don't have the same type and name.")
return r
}
// Unload plugin
up := c.UnloadPlugin(unloadType, unloadName, unloadVersion)
if up.Err != nil {
r.Err = up.Err
up2 := c.UnloadPlugin(lpr.Type, lpr.Name, lpr.Version)
if up2.Err != nil {
r.Err = errors.New("Failed to rollback after error unloading plugin.")
}
return r
}
upr := up.PluginUnloaded
r.LoadedPlugin = lp.LoadedPlugins[0]
r.UnloadedPlugin = upr
return r
}

// GetPlugins returns the loaded and available plugins through an HTTP GET request.
// By specifying the details flag to tweak output info. An error returns if it failed.
func (c *Client) GetPlugins(details bool) *GetPluginsResult {
Expand Down Expand Up @@ -131,6 +177,12 @@ type UnloadPluginResult struct {
Err error
}

type SwapPluginsResult struct {
LoadedPlugin LoadedPlugin
UnloadedPlugin *rbody.PluginUnloaded
Err error
}

// We wrap this so we can provide some functionality (like LoadedTime)
type LoadedPlugin struct {
*rbody.LoadedPlugin
Expand Down

0 comments on commit e9abb1d

Please sign in to comment.