Skip to content
This repository has been archived by the owner on Jan 21, 2020. It is now read-only.

Commit

Permalink
Metadata SPI (#396)
Browse files Browse the repository at this point in the history
Signed-off-by: David Chung <[email protected]>
  • Loading branch information
David Chung authored Feb 20, 2017
1 parent 050a6a9 commit 7841ecd
Show file tree
Hide file tree
Showing 27 changed files with 1,744 additions and 70 deletions.
4 changes: 2 additions & 2 deletions cmd/cli/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func infoCommand(plugins func() discovery.Plugins) *cobra.Command {
return err
}

view, err := renderer.AddDef("plugin", *name).Render(info)
view, err := renderer.Def("plugin", *name, "Plugin name").Render(info)
if err != nil {
return err
}
Expand Down Expand Up @@ -103,7 +103,7 @@ func infoCommand(plugins func() discovery.Plugins) *cobra.Command {
return err
}

view, err := renderer.AddDef("plugin", *name).Render(info)
view, err := renderer.Def("plugin", *name, "Plugin name").Render(info)
if err != nil {
return err
}
Expand Down
5 changes: 4 additions & 1 deletion cmd/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ func main() {
cmd.AddCommand(infoCommand(f))
cmd.AddCommand(templateCommand(f))
cmd.AddCommand(managerCommand(f))
cmd.AddCommand(pluginCommand(f), instancePluginCommand(f), groupPluginCommand(f), flavorPluginCommand(f))
cmd.AddCommand(metadataCommand(f))
cmd.AddCommand(pluginCommand(f))

cmd.AddCommand(instancePluginCommand(f), groupPluginCommand(f), flavorPluginCommand(f))

err := cmd.Execute()
if err != nil {
Expand Down
219 changes: 219 additions & 0 deletions cmd/cli/metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
package main

import (
"fmt"
"strconv"

log "github.com/Sirupsen/logrus"
"github.com/docker/infrakit/pkg/discovery"
metadata_plugin "github.com/docker/infrakit/pkg/plugin/metadata"
"github.com/docker/infrakit/pkg/rpc/client"
metadata_rpc "github.com/docker/infrakit/pkg/rpc/metadata"
"github.com/docker/infrakit/pkg/spi/metadata"
"github.com/spf13/cobra"
)

func getPlugin(plugins func() discovery.Plugins, name string) (found metadata.Plugin, err error) {
err = forPlugin(plugins, func(n string, p metadata.Plugin) error {
if n == name {
found = p
}
return nil
})
return
}

func forPlugin(plugins func() discovery.Plugins, do func(string, metadata.Plugin) error) error {
all, err := plugins().List()
if err != nil {
return err
}
for name, endpoint := range all {
rpcClient, err := client.New(endpoint.Address, metadata.InterfaceSpec)
if err != nil {
continue
}
if err := do(name, metadata_rpc.Adapt(rpcClient)); err != nil {
return err
}
}
return nil
}

func listAll(m metadata.Plugin, path metadata.Path) ([]metadata.Path, error) {
if m == nil {
return nil, fmt.Errorf("no plugin")
}
result := []metadata.Path{}
nodes, err := m.List(path)
if err != nil {
return nil, err
}
for _, n := range nodes {
c := path.Join(n)
more, err := listAll(m, c)
if err != nil {
return nil, err
}
if len(more) == 0 {
result = append(result, c)
}
for _, pp := range more {
result = append(result, pp)
}
}
return result, nil
}

func metadataCommand(plugins func() discovery.Plugins) *cobra.Command {

cmd := &cobra.Command{
Use: "metadata",
Short: "Access metadata exposed by infrakit plugins",
}

ls := &cobra.Command{
Use: "ls",
Short: "List all metadata entries",
}

long := ls.Flags().BoolP("long", "l", false, "Print full path")
all := ls.Flags().BoolP("all", "a", false, "Find all under the paths given")

ls.RunE = func(c *cobra.Command, args []string) error {
paths := []string{"."}

// All implies long
if *all {
*long = true
}

if len(args) > 0 {
paths = args
}

for _, p := range paths {

if p == "/" {
// TODO(chungers) -- this is a 'local' infrakit ensemble.
// Absolute paths will come in a multi-cluster / federated model.
return fmt.Errorf("No absolute path")
}

path := metadata_plugin.Path(p)
first := path.Index(0)

targets := []string{} // target plugins to query

// Check all the plugins -- scanning via discovery
if err := forPlugin(plugins,
func(name string, mp metadata.Plugin) error {
if p == "." || (first != nil && name == *first) {
targets = append(targets, name)
}
return nil
}); err != nil {
return err
}

for _, target := range targets {

nodes := []metadata.Path{} // the result set to print

match, err := getPlugin(plugins, target)
if err != nil {
return err
}

if p == "." {
if *all {
allPaths, err := listAll(match, path.Shift(1))
if err != nil {
log.Warningln("Cannot metadata ls on plugin", target, "err=", err)
}
for _, c := range allPaths {
nodes = append(nodes, metadata_plugin.Path(target).Sub(c))
}
} else {
for _, t := range targets {
nodes = append(nodes, metadata_plugin.Path(t))
}
}
} else {
if *all {
allPaths, err := listAll(match, path.Shift(1))
if err != nil {
log.Warningln("Cannot metadata ls on plugin", target, "err=", err)
}
for _, c := range allPaths {
nodes = append(nodes, metadata_plugin.Path(target).Sub(c))
}
} else {
children, err := match.List(path.Shift(1))
if err != nil {
log.Warningln("Cannot metadata ls on plugin", target, "err=", err)
}
for _, c := range children {
nodes = append(nodes, path.Join(c))
}
}
}

if len(targets) > 1 {
fmt.Printf("%s:\n", target)
}
if *long {
fmt.Printf("total %d:\n", len(nodes))
}
for _, l := range nodes {
if *long {
fmt.Println(metadata_plugin.String(l))
} else {
fmt.Println(metadata_plugin.String(l.Rel(path)))
}
}
fmt.Println()
}

}
return nil
}

cat := &cobra.Command{
Use: "cat",
Short: "Get metadata entry by path",
RunE: func(c *cobra.Command, args []string) error {

for _, p := range args {

path := metadata_plugin.Path(p)
first := path.Index(0)
if first != nil {
match, err := getPlugin(plugins, *first)
if err != nil {
return err
}

value, err := match.Get(path.Shift(1))
if err == nil {
if value != nil {
str := value.String()
if s, err := strconv.Unquote(value.String()); err == nil {
str = s
}
fmt.Println(str)
}

} else {
log.Warningln("Cannot metadata cat on plugin", *first, "err=", err)
}
}
}
return nil
},
}

cmd.AddCommand(ls, cat)

return cmd
}
16 changes: 16 additions & 0 deletions cmd/cli/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

log "github.com/Sirupsen/logrus"
"github.com/docker/infrakit/pkg/discovery"
metadata_template "github.com/docker/infrakit/pkg/plugin/metadata/template"
"github.com/docker/infrakit/pkg/template"
"github.com/spf13/cobra"
)
Expand All @@ -24,6 +25,21 @@ func templateCommand(plugins func() discovery.Plugins) *cobra.Command {
if err != nil {
return err
}

// Add functions
engine.WithFunctions(func() []template.Function {
return []template.Function{
{
Name: "metadata",
Description: []string{
"Metadata function takes a path of the form \"plugin_name/path/to/data\"",
"and calls GET on the plugin with the path \"path/to/data\".",
"It's identical to the CLI command infrakit metadata cat ...",
},
Func: metadata_template.MetadataFunc(plugins),
},
}
})
view, err := engine.Render(nil)
if err != nil {
return err
Expand Down
48 changes: 48 additions & 0 deletions examples/flavor/swarm/flavor.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import (
"github.com/docker/docker/client"
"github.com/docker/go-connections/tlsconfig"
group_types "github.com/docker/infrakit/pkg/plugin/group/types"
metadata_plugin "github.com/docker/infrakit/pkg/plugin/metadata"
"github.com/docker/infrakit/pkg/spi/flavor"
"github.com/docker/infrakit/pkg/spi/instance"
"github.com/docker/infrakit/pkg/spi/metadata"
"github.com/docker/infrakit/pkg/template"
"github.com/docker/infrakit/pkg/types"
"github.com/docker/infrakit/pkg/util/docker"
Expand Down Expand Up @@ -64,6 +66,52 @@ type baseFlavor struct {
initScript *template.Template
}

// List implements the metadata.Plugin SPI's List method
func (s *baseFlavor) List(path metadata.Path) ([]string, error) {
docker, err := s.getDockerClient(Spec{
Docker: ConnectInfo{
Host: "unix:///var/run/docker.sock", // defaults to local socket
},
})
if err != nil {
return nil, err
}
status, node, err := swarmState(docker)
if err != nil {
return nil, err
}
data := map[string]interface{}{
"local": map[string]interface{}{
"status": status,
"node": node,
},
}
return metadata_plugin.List(path, data), nil
}

// Get implements the metadata.Plugin SPI's List method
func (s *baseFlavor) Get(path metadata.Path) (*types.Any, error) {
docker, err := s.getDockerClient(Spec{
Docker: ConnectInfo{
Host: "unix:///var/run/docker.sock", // defaults to local socket
},
})
if err != nil {
return nil, err
}
status, node, err := swarmState(docker)
if err != nil {
return nil, err
}
data := map[string]interface{}{
"local": map[string]interface{}{
"status": status,
"node": node,
},
}
return metadata_plugin.GetValue(path, data)
}

// Funcs implements the template.FunctionExporter interface that allows the RPC server to expose help on the
// functions it exports
func (s *baseFlavor) Funcs() []template.Function {
Expand Down
32 changes: 26 additions & 6 deletions examples/flavor/swarm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/docker/infrakit/pkg/cli"
"github.com/docker/infrakit/pkg/discovery"
"github.com/docker/infrakit/pkg/plugin/metadata"
flavor_plugin "github.com/docker/infrakit/pkg/rpc/flavor"
"github.com/docker/infrakit/pkg/spi/flavor"
metadata_plugin "github.com/docker/infrakit/pkg/rpc/metadata"
flavor_spi "github.com/docker/infrakit/pkg/spi/flavor"
metadata_spi "github.com/docker/infrakit/pkg/spi/metadata"
"github.com/docker/infrakit/pkg/template"
"github.com/docker/infrakit/pkg/util/docker"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -48,11 +51,28 @@ func main() {
return err
}

cli.RunPlugin(*name, flavor_plugin.PluginServerWithTypes(
map[string]flavor.Plugin{
"manager": NewManagerFlavor(DockerClient, mt),
"worker": NewWorkerFlavor(DockerClient, wt),
}))
managerFlavor := NewManagerFlavor(DockerClient, mt)
workerFlavor := NewWorkerFlavor(DockerClient, wt)

cli.RunPlugin(*name,

// Metadata plugins
metadata_plugin.PluginServer(metadata.NewPluginFromData(map[string]interface{}{
"version": cli.Version,
"revision": cli.Revision,
"implements": flavor_spi.InterfaceSpec,
})).WithTypes(
map[string]metadata_spi.Plugin{
"manager": managerFlavor,
"worker": workerFlavor,
}),

// Flavor plugins
flavor_plugin.PluginServerWithTypes(
map[string]flavor_spi.Plugin{
"manager": managerFlavor,
"worker": workerFlavor,
}))
return nil
}

Expand Down
Loading

0 comments on commit 7841ecd

Please sign in to comment.