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

Commit 7841ecd

Browse files
author
David Chung
authored
Metadata SPI (#396)
Signed-off-by: David Chung <[email protected]>
1 parent 050a6a9 commit 7841ecd

27 files changed

+1744
-70
lines changed

cmd/cli/info.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func infoCommand(plugins func() discovery.Plugins) *cobra.Command {
6767
return err
6868
}
6969

70-
view, err := renderer.AddDef("plugin", *name).Render(info)
70+
view, err := renderer.Def("plugin", *name, "Plugin name").Render(info)
7171
if err != nil {
7272
return err
7373
}
@@ -103,7 +103,7 @@ func infoCommand(plugins func() discovery.Plugins) *cobra.Command {
103103
return err
104104
}
105105

106-
view, err := renderer.AddDef("plugin", *name).Render(info)
106+
view, err := renderer.Def("plugin", *name, "Plugin name").Render(info)
107107
if err != nil {
108108
return err
109109
}

cmd/cli/main.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ func main() {
4343
cmd.AddCommand(infoCommand(f))
4444
cmd.AddCommand(templateCommand(f))
4545
cmd.AddCommand(managerCommand(f))
46-
cmd.AddCommand(pluginCommand(f), instancePluginCommand(f), groupPluginCommand(f), flavorPluginCommand(f))
46+
cmd.AddCommand(metadataCommand(f))
47+
cmd.AddCommand(pluginCommand(f))
48+
49+
cmd.AddCommand(instancePluginCommand(f), groupPluginCommand(f), flavorPluginCommand(f))
4750

4851
err := cmd.Execute()
4952
if err != nil {

cmd/cli/metadata.go

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
7+
log "github.com/Sirupsen/logrus"
8+
"github.com/docker/infrakit/pkg/discovery"
9+
metadata_plugin "github.com/docker/infrakit/pkg/plugin/metadata"
10+
"github.com/docker/infrakit/pkg/rpc/client"
11+
metadata_rpc "github.com/docker/infrakit/pkg/rpc/metadata"
12+
"github.com/docker/infrakit/pkg/spi/metadata"
13+
"github.com/spf13/cobra"
14+
)
15+
16+
func getPlugin(plugins func() discovery.Plugins, name string) (found metadata.Plugin, err error) {
17+
err = forPlugin(plugins, func(n string, p metadata.Plugin) error {
18+
if n == name {
19+
found = p
20+
}
21+
return nil
22+
})
23+
return
24+
}
25+
26+
func forPlugin(plugins func() discovery.Plugins, do func(string, metadata.Plugin) error) error {
27+
all, err := plugins().List()
28+
if err != nil {
29+
return err
30+
}
31+
for name, endpoint := range all {
32+
rpcClient, err := client.New(endpoint.Address, metadata.InterfaceSpec)
33+
if err != nil {
34+
continue
35+
}
36+
if err := do(name, metadata_rpc.Adapt(rpcClient)); err != nil {
37+
return err
38+
}
39+
}
40+
return nil
41+
}
42+
43+
func listAll(m metadata.Plugin, path metadata.Path) ([]metadata.Path, error) {
44+
if m == nil {
45+
return nil, fmt.Errorf("no plugin")
46+
}
47+
result := []metadata.Path{}
48+
nodes, err := m.List(path)
49+
if err != nil {
50+
return nil, err
51+
}
52+
for _, n := range nodes {
53+
c := path.Join(n)
54+
more, err := listAll(m, c)
55+
if err != nil {
56+
return nil, err
57+
}
58+
if len(more) == 0 {
59+
result = append(result, c)
60+
}
61+
for _, pp := range more {
62+
result = append(result, pp)
63+
}
64+
}
65+
return result, nil
66+
}
67+
68+
func metadataCommand(plugins func() discovery.Plugins) *cobra.Command {
69+
70+
cmd := &cobra.Command{
71+
Use: "metadata",
72+
Short: "Access metadata exposed by infrakit plugins",
73+
}
74+
75+
ls := &cobra.Command{
76+
Use: "ls",
77+
Short: "List all metadata entries",
78+
}
79+
80+
long := ls.Flags().BoolP("long", "l", false, "Print full path")
81+
all := ls.Flags().BoolP("all", "a", false, "Find all under the paths given")
82+
83+
ls.RunE = func(c *cobra.Command, args []string) error {
84+
paths := []string{"."}
85+
86+
// All implies long
87+
if *all {
88+
*long = true
89+
}
90+
91+
if len(args) > 0 {
92+
paths = args
93+
}
94+
95+
for _, p := range paths {
96+
97+
if p == "/" {
98+
// TODO(chungers) -- this is a 'local' infrakit ensemble.
99+
// Absolute paths will come in a multi-cluster / federated model.
100+
return fmt.Errorf("No absolute path")
101+
}
102+
103+
path := metadata_plugin.Path(p)
104+
first := path.Index(0)
105+
106+
targets := []string{} // target plugins to query
107+
108+
// Check all the plugins -- scanning via discovery
109+
if err := forPlugin(plugins,
110+
func(name string, mp metadata.Plugin) error {
111+
if p == "." || (first != nil && name == *first) {
112+
targets = append(targets, name)
113+
}
114+
return nil
115+
}); err != nil {
116+
return err
117+
}
118+
119+
for _, target := range targets {
120+
121+
nodes := []metadata.Path{} // the result set to print
122+
123+
match, err := getPlugin(plugins, target)
124+
if err != nil {
125+
return err
126+
}
127+
128+
if p == "." {
129+
if *all {
130+
allPaths, err := listAll(match, path.Shift(1))
131+
if err != nil {
132+
log.Warningln("Cannot metadata ls on plugin", target, "err=", err)
133+
}
134+
for _, c := range allPaths {
135+
nodes = append(nodes, metadata_plugin.Path(target).Sub(c))
136+
}
137+
} else {
138+
for _, t := range targets {
139+
nodes = append(nodes, metadata_plugin.Path(t))
140+
}
141+
}
142+
} else {
143+
if *all {
144+
allPaths, err := listAll(match, path.Shift(1))
145+
if err != nil {
146+
log.Warningln("Cannot metadata ls on plugin", target, "err=", err)
147+
}
148+
for _, c := range allPaths {
149+
nodes = append(nodes, metadata_plugin.Path(target).Sub(c))
150+
}
151+
} else {
152+
children, err := match.List(path.Shift(1))
153+
if err != nil {
154+
log.Warningln("Cannot metadata ls on plugin", target, "err=", err)
155+
}
156+
for _, c := range children {
157+
nodes = append(nodes, path.Join(c))
158+
}
159+
}
160+
}
161+
162+
if len(targets) > 1 {
163+
fmt.Printf("%s:\n", target)
164+
}
165+
if *long {
166+
fmt.Printf("total %d:\n", len(nodes))
167+
}
168+
for _, l := range nodes {
169+
if *long {
170+
fmt.Println(metadata_plugin.String(l))
171+
} else {
172+
fmt.Println(metadata_plugin.String(l.Rel(path)))
173+
}
174+
}
175+
fmt.Println()
176+
}
177+
178+
}
179+
return nil
180+
}
181+
182+
cat := &cobra.Command{
183+
Use: "cat",
184+
Short: "Get metadata entry by path",
185+
RunE: func(c *cobra.Command, args []string) error {
186+
187+
for _, p := range args {
188+
189+
path := metadata_plugin.Path(p)
190+
first := path.Index(0)
191+
if first != nil {
192+
match, err := getPlugin(plugins, *first)
193+
if err != nil {
194+
return err
195+
}
196+
197+
value, err := match.Get(path.Shift(1))
198+
if err == nil {
199+
if value != nil {
200+
str := value.String()
201+
if s, err := strconv.Unquote(value.String()); err == nil {
202+
str = s
203+
}
204+
fmt.Println(str)
205+
}
206+
207+
} else {
208+
log.Warningln("Cannot metadata cat on plugin", *first, "err=", err)
209+
}
210+
}
211+
}
212+
return nil
213+
},
214+
}
215+
216+
cmd.AddCommand(ls, cat)
217+
218+
return cmd
219+
}

cmd/cli/template.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
log "github.com/Sirupsen/logrus"
77
"github.com/docker/infrakit/pkg/discovery"
8+
metadata_template "github.com/docker/infrakit/pkg/plugin/metadata/template"
89
"github.com/docker/infrakit/pkg/template"
910
"github.com/spf13/cobra"
1011
)
@@ -24,6 +25,21 @@ func templateCommand(plugins func() discovery.Plugins) *cobra.Command {
2425
if err != nil {
2526
return err
2627
}
28+
29+
// Add functions
30+
engine.WithFunctions(func() []template.Function {
31+
return []template.Function{
32+
{
33+
Name: "metadata",
34+
Description: []string{
35+
"Metadata function takes a path of the form \"plugin_name/path/to/data\"",
36+
"and calls GET on the plugin with the path \"path/to/data\".",
37+
"It's identical to the CLI command infrakit metadata cat ...",
38+
},
39+
Func: metadata_template.MetadataFunc(plugins),
40+
},
41+
}
42+
})
2743
view, err := engine.Render(nil)
2844
if err != nil {
2945
return err

examples/flavor/swarm/flavor.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ import (
1111
"github.com/docker/docker/client"
1212
"github.com/docker/go-connections/tlsconfig"
1313
group_types "github.com/docker/infrakit/pkg/plugin/group/types"
14+
metadata_plugin "github.com/docker/infrakit/pkg/plugin/metadata"
1415
"github.com/docker/infrakit/pkg/spi/flavor"
1516
"github.com/docker/infrakit/pkg/spi/instance"
17+
"github.com/docker/infrakit/pkg/spi/metadata"
1618
"github.com/docker/infrakit/pkg/template"
1719
"github.com/docker/infrakit/pkg/types"
1820
"github.com/docker/infrakit/pkg/util/docker"
@@ -64,6 +66,52 @@ type baseFlavor struct {
6466
initScript *template.Template
6567
}
6668

69+
// List implements the metadata.Plugin SPI's List method
70+
func (s *baseFlavor) List(path metadata.Path) ([]string, error) {
71+
docker, err := s.getDockerClient(Spec{
72+
Docker: ConnectInfo{
73+
Host: "unix:///var/run/docker.sock", // defaults to local socket
74+
},
75+
})
76+
if err != nil {
77+
return nil, err
78+
}
79+
status, node, err := swarmState(docker)
80+
if err != nil {
81+
return nil, err
82+
}
83+
data := map[string]interface{}{
84+
"local": map[string]interface{}{
85+
"status": status,
86+
"node": node,
87+
},
88+
}
89+
return metadata_plugin.List(path, data), nil
90+
}
91+
92+
// Get implements the metadata.Plugin SPI's List method
93+
func (s *baseFlavor) Get(path metadata.Path) (*types.Any, error) {
94+
docker, err := s.getDockerClient(Spec{
95+
Docker: ConnectInfo{
96+
Host: "unix:///var/run/docker.sock", // defaults to local socket
97+
},
98+
})
99+
if err != nil {
100+
return nil, err
101+
}
102+
status, node, err := swarmState(docker)
103+
if err != nil {
104+
return nil, err
105+
}
106+
data := map[string]interface{}{
107+
"local": map[string]interface{}{
108+
"status": status,
109+
"node": node,
110+
},
111+
}
112+
return metadata_plugin.GetValue(path, data)
113+
}
114+
67115
// Funcs implements the template.FunctionExporter interface that allows the RPC server to expose help on the
68116
// functions it exports
69117
func (s *baseFlavor) Funcs() []template.Function {

examples/flavor/swarm/main.go

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ import (
66
log "github.com/Sirupsen/logrus"
77
"github.com/docker/infrakit/pkg/cli"
88
"github.com/docker/infrakit/pkg/discovery"
9+
"github.com/docker/infrakit/pkg/plugin/metadata"
910
flavor_plugin "github.com/docker/infrakit/pkg/rpc/flavor"
10-
"github.com/docker/infrakit/pkg/spi/flavor"
11+
metadata_plugin "github.com/docker/infrakit/pkg/rpc/metadata"
12+
flavor_spi "github.com/docker/infrakit/pkg/spi/flavor"
13+
metadata_spi "github.com/docker/infrakit/pkg/spi/metadata"
1114
"github.com/docker/infrakit/pkg/template"
1215
"github.com/docker/infrakit/pkg/util/docker"
1316
"github.com/spf13/cobra"
@@ -48,11 +51,28 @@ func main() {
4851
return err
4952
}
5053

51-
cli.RunPlugin(*name, flavor_plugin.PluginServerWithTypes(
52-
map[string]flavor.Plugin{
53-
"manager": NewManagerFlavor(DockerClient, mt),
54-
"worker": NewWorkerFlavor(DockerClient, wt),
55-
}))
54+
managerFlavor := NewManagerFlavor(DockerClient, mt)
55+
workerFlavor := NewWorkerFlavor(DockerClient, wt)
56+
57+
cli.RunPlugin(*name,
58+
59+
// Metadata plugins
60+
metadata_plugin.PluginServer(metadata.NewPluginFromData(map[string]interface{}{
61+
"version": cli.Version,
62+
"revision": cli.Revision,
63+
"implements": flavor_spi.InterfaceSpec,
64+
})).WithTypes(
65+
map[string]metadata_spi.Plugin{
66+
"manager": managerFlavor,
67+
"worker": workerFlavor,
68+
}),
69+
70+
// Flavor plugins
71+
flavor_plugin.PluginServerWithTypes(
72+
map[string]flavor_spi.Plugin{
73+
"manager": managerFlavor,
74+
"worker": workerFlavor,
75+
}))
5676
return nil
5777
}
5878

0 commit comments

Comments
 (0)