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

Commit 8ba08a1

Browse files
author
David Chung
authored
Updatable SPI (#491)
Signed-off-by: David Chung <[email protected]>
1 parent f2f738c commit 8ba08a1

File tree

30 files changed

+3605
-51
lines changed

30 files changed

+3605
-51
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ ifneq (,$(findstring .m,$(VERSION)))
119119
@echo "\nWARNING - repository contains uncommitted changes, tagging binaries as dirty\n"
120120
endif
121121

122-
$(call build_binary,infrakit,github.com/docker/infrakit/cmd/cli/main)
122+
$(call build_binary,infrakit,github.com/docker/infrakit/cmd/cli)
123123
$(call build_binary,infrakit-manager,github.com/docker/infrakit/cmd/manager)
124124
$(call build_binary,infrakit-group-default,github.com/docker/infrakit/cmd/group)
125125
$(call build_binary,infrakit-resource,github.com/docker/infrakit/cmd/resource)
@@ -142,7 +142,7 @@ build-cli:
142142
ifneq (,$(findstring .m,$(VERSION)))
143143
@echo "\nWARNING - repository contains uncommitted changes, tagging binaries as dirty\n"
144144
endif
145-
$(call build_binary,infrakit,github.com/docker/infrakit/cmd/cli/main)
145+
$(call build_binary,infrakit,github.com/docker/infrakit/cmd/cli)
146146

147147
install:
148148
@echo "+ $@"

cmd/cli/main/main.go renamed to cmd/cli/main.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ import (
1919
_ "github.com/docker/infrakit/cmd/cli/event"
2020
_ "github.com/docker/infrakit/cmd/cli/flavor"
2121
_ "github.com/docker/infrakit/cmd/cli/group"
22+
_ "github.com/docker/infrakit/cmd/cli/info"
23+
_ "github.com/docker/infrakit/cmd/cli/instance"
2224
_ "github.com/docker/infrakit/cmd/cli/manager"
23-
_ "github.com/docker/infrakit/cmd/cli/playbook"
25+
_ "github.com/docker/infrakit/cmd/cli/metadata"
2426
_ "github.com/docker/infrakit/cmd/cli/plugin"
2527
_ "github.com/docker/infrakit/cmd/cli/resource"
2628
_ "github.com/docker/infrakit/cmd/cli/template"

cmd/cli/main/init.go

Lines changed: 0 additions & 15 deletions
This file was deleted.

cmd/cli/manager/manager.go

Lines changed: 192 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package manager
22

33
import (
4+
"bufio"
45
"fmt"
56
"os"
7+
"strconv"
8+
"strings"
69

710
"github.com/docker/infrakit/cmd/cli/base"
811
"github.com/docker/infrakit/pkg/cli"
@@ -11,10 +14,13 @@ import (
1114
"github.com/docker/infrakit/pkg/manager"
1215
"github.com/docker/infrakit/pkg/plugin"
1316
"github.com/docker/infrakit/pkg/rpc/client"
14-
group_plugin "github.com/docker/infrakit/pkg/rpc/group"
17+
group_rpc "github.com/docker/infrakit/pkg/rpc/group"
1518
manager_rpc "github.com/docker/infrakit/pkg/rpc/manager"
19+
metadata_rpc "github.com/docker/infrakit/pkg/rpc/metadata"
1620
"github.com/docker/infrakit/pkg/spi/group"
21+
"github.com/docker/infrakit/pkg/spi/metadata"
1722
"github.com/docker/infrakit/pkg/types"
23+
"github.com/sergi/go-diff/diffmatchpatch"
1824
"github.com/spf13/cobra"
1925
)
2026

@@ -30,6 +36,9 @@ func Command(plugins func() discovery.Plugins) *cobra.Command {
3036
var groupPlugin group.Plugin
3137
var groupPluginName string
3238

39+
var updatablePlugin metadata.Updatable
40+
var updatablePluginName string
41+
3342
cmd := &cobra.Command{
3443
Use: "manager",
3544
Short: "Access the manager",
@@ -59,11 +68,15 @@ func Command(plugins func() discovery.Plugins) *cobra.Command {
5968
log.Debug("Found manager", "name", name, "leader", isLeader)
6069
if isLeader {
6170

62-
groupPlugin = group_plugin.Adapt(rpcClient)
71+
groupPlugin = group_rpc.Adapt(rpcClient)
6372
groupPluginName = name
6473

6574
log.Debug("Found manager", "name", name, "addr", endpoint.Address)
6675

76+
updatablePlugin = metadata_rpc.AdaptUpdatable(rpcClient)
77+
updatablePluginName = name
78+
79+
log.Debug("Found updatable", "name", name, "addr", endpoint.Address)
6780
break
6881
}
6982
}
@@ -132,7 +145,7 @@ func Command(plugins func() discovery.Plugins) *cobra.Command {
132145

133146
// TODO(chungers) -- we need to enforce and confirm the type of this.
134147
// Right now we assume the RPC endpoint is indeed a group.
135-
target, err := group_plugin.NewClient(endpoint.Address)
148+
target, err := group_rpc.NewClient(endpoint.Address)
136149

137150
log.Debug("commit", "plugin", gp.Plugin, "address", endpoint.Address, "err", err, "spec", spec)
138151

@@ -165,26 +178,11 @@ func Command(plugins func() discovery.Plugins) *cobra.Command {
165178
os.Exit(1)
166179
}
167180

168-
specs, err := groupPlugin.InspectGroups()
181+
out, err := getGlobalConfig(groupPlugin, groupPluginName)
169182
if err != nil {
170183
return err
171184
}
172185

173-
// the format is plugin.Spec
174-
out := []plugin.Spec{}
175-
for _, spec := range specs {
176-
177-
any, err := types.AnyValue(spec)
178-
if err != nil {
179-
return err
180-
}
181-
182-
out = append(out, plugin.Spec{
183-
Plugin: plugin.Name(groupPluginName),
184-
Properties: any,
185-
})
186-
}
187-
188186
view, err := types.AnyValue(out)
189187
if err != nil {
190188
return err
@@ -202,7 +200,181 @@ func Command(plugins func() discovery.Plugins) *cobra.Command {
202200
}
203201
inspect.Flags().AddFlagSet(templateFlags)
204202

205-
cmd.AddCommand(commit, inspect)
203+
///////////////////////////////////////////////////////////////////////////////////
204+
// change
205+
change := &cobra.Command{
206+
Use: "change",
207+
Short: "Change returns the plugin configurations known by the manager",
208+
}
209+
vars := change.Flags().StringSliceP("var", "v", []string{}, "key=value pairs")
210+
commitChange := change.Flags().BoolP("commit", "c", false, "Commit changes")
211+
212+
// This is the only interactive command. We want to show the user the proposal, with the diff
213+
// and when the user accepts the change, call a commit.
214+
change.RunE = func(cmd *cobra.Command, args []string) error {
215+
216+
if len(args) != 0 {
217+
cmd.Usage()
218+
os.Exit(1)
219+
}
220+
221+
log.Info("applying changes")
222+
223+
// get the changes
224+
changes, err := changeSet(*vars)
225+
if err != nil {
226+
return err
227+
}
228+
current, proposed, cas, err := updatablePlugin.Changes(changes)
229+
if err != nil {
230+
return err
231+
}
232+
currentBuff, err := current.MarshalYAML()
233+
if err != nil {
234+
return err
235+
}
236+
237+
proposedBuff, err := proposed.MarshalYAML()
238+
if err != nil {
239+
return err
240+
}
241+
242+
// render the proposal
243+
fmt.Printf("Proposed changes, hash=%s\n", cas)
244+
dmp := diffmatchpatch.New()
245+
diffs := dmp.DiffMain(string(currentBuff), string(proposedBuff), false)
246+
fmt.Println(dmp.DiffPrettyText(diffs))
247+
248+
if *commitChange {
249+
// ask for final approval
250+
input := bufio.NewReader(os.Stdin)
251+
fmt.Fprintf(os.Stderr, "\n\nCommit? [y/n] ")
252+
text, _ := input.ReadString('\n')
253+
text = strings.Trim(text, " \t\n")
254+
255+
agree, err := parseBool(text)
256+
if err != nil {
257+
return fmt.Errorf("not boolean %v", text)
258+
}
259+
if !agree {
260+
fmt.Fprintln(os.Stderr, "Not committing. Bye.")
261+
os.Exit(0)
262+
}
263+
264+
return updatablePlugin.Commit(proposed, cas)
265+
}
266+
267+
return nil
268+
}
269+
change.Flags().AddFlagSet(templateFlags)
270+
271+
///////////////////////////////////////////////////////////////////////////////////
272+
// change-list
273+
changeList := &cobra.Command{
274+
Use: "ls",
275+
Short: "Lists all the changeable paths",
276+
RunE: func(cmd *cobra.Command, args []string) error {
277+
278+
if len(args) != 0 {
279+
cmd.Usage()
280+
os.Exit(1)
281+
}
282+
283+
all, err := types.ListAll(updatablePlugin, types.PathFromString("."))
284+
if err != nil {
285+
return err
286+
}
287+
288+
types.Sort(all)
289+
for _, p := range all {
290+
fmt.Println(p.String())
291+
}
292+
return nil
293+
},
294+
}
295+
///////////////////////////////////////////////////////////////////////////////////
296+
// change-cat
297+
changeGet := &cobra.Command{
298+
Use: "cat",
299+
Short: "Cat returns the current value at given path",
300+
RunE: func(cmd *cobra.Command, args []string) error {
301+
302+
if len(args) != 1 {
303+
cmd.Usage()
304+
os.Exit(1)
305+
}
306+
307+
path := types.PathFromString(args[0])
308+
any, err := updatablePlugin.Get(path)
309+
if err != nil {
310+
return err
311+
}
312+
313+
fmt.Println(any.String())
314+
315+
return nil
316+
},
317+
}
318+
change.AddCommand(changeList, changeGet)
319+
320+
cmd.AddCommand(commit, inspect, change)
206321

207322
return cmd
208323
}
324+
325+
func parseBool(text string) (bool, error) {
326+
agree, err := strconv.ParseBool(text)
327+
if err == nil {
328+
return agree, nil
329+
}
330+
switch strings.ToLower(text) {
331+
case "yes", "ok", "y":
332+
return true, nil
333+
case "no", "nope", "n":
334+
return false, nil
335+
}
336+
return false, err
337+
}
338+
339+
func getGlobalConfig(groupPlugin group.Plugin, groupPluginName string) ([]plugin.Spec, error) {
340+
specs, err := groupPlugin.InspectGroups()
341+
if err != nil {
342+
return nil, err
343+
}
344+
345+
// the format is plugin.Spec
346+
out := []plugin.Spec{}
347+
for _, spec := range specs {
348+
349+
any, err := types.AnyValue(spec)
350+
if err != nil {
351+
return nil, err
352+
}
353+
354+
out = append(out, plugin.Spec{
355+
Plugin: plugin.Name(groupPluginName),
356+
Properties: any,
357+
})
358+
}
359+
return out, nil
360+
}
361+
362+
// changeSet returns a set of changes from the input pairs of path / value
363+
func changeSet(kvPairs []string) ([]metadata.Change, error) {
364+
changes := []metadata.Change{}
365+
366+
for _, kv := range kvPairs {
367+
368+
parts := strings.SplitN(kv, "=", 2)
369+
key := strings.Trim(parts[0], " \t\n")
370+
value := strings.Trim(parts[1], " \t\n")
371+
372+
change := metadata.Change{
373+
Path: types.PathFromString(key),
374+
Value: types.AnyYAMLMust([]byte(value)),
375+
}
376+
377+
changes = append(changes, change)
378+
}
379+
return changes, nil
380+
}

0 commit comments

Comments
 (0)