1
1
package manager
2
2
3
3
import (
4
+ "bufio"
4
5
"fmt"
5
6
"os"
7
+ "strconv"
8
+ "strings"
6
9
7
10
"github.com/docker/infrakit/cmd/cli/base"
8
11
"github.com/docker/infrakit/pkg/cli"
@@ -11,10 +14,13 @@ import (
11
14
"github.com/docker/infrakit/pkg/manager"
12
15
"github.com/docker/infrakit/pkg/plugin"
13
16
"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"
15
18
manager_rpc "github.com/docker/infrakit/pkg/rpc/manager"
19
+ metadata_rpc "github.com/docker/infrakit/pkg/rpc/metadata"
16
20
"github.com/docker/infrakit/pkg/spi/group"
21
+ "github.com/docker/infrakit/pkg/spi/metadata"
17
22
"github.com/docker/infrakit/pkg/types"
23
+ "github.com/sergi/go-diff/diffmatchpatch"
18
24
"github.com/spf13/cobra"
19
25
)
20
26
@@ -30,6 +36,9 @@ func Command(plugins func() discovery.Plugins) *cobra.Command {
30
36
var groupPlugin group.Plugin
31
37
var groupPluginName string
32
38
39
+ var updatablePlugin metadata.Updatable
40
+ var updatablePluginName string
41
+
33
42
cmd := & cobra.Command {
34
43
Use : "manager" ,
35
44
Short : "Access the manager" ,
@@ -59,11 +68,15 @@ func Command(plugins func() discovery.Plugins) *cobra.Command {
59
68
log .Debug ("Found manager" , "name" , name , "leader" , isLeader )
60
69
if isLeader {
61
70
62
- groupPlugin = group_plugin .Adapt (rpcClient )
71
+ groupPlugin = group_rpc .Adapt (rpcClient )
63
72
groupPluginName = name
64
73
65
74
log .Debug ("Found manager" , "name" , name , "addr" , endpoint .Address )
66
75
76
+ updatablePlugin = metadata_rpc .AdaptUpdatable (rpcClient )
77
+ updatablePluginName = name
78
+
79
+ log .Debug ("Found updatable" , "name" , name , "addr" , endpoint .Address )
67
80
break
68
81
}
69
82
}
@@ -132,7 +145,7 @@ func Command(plugins func() discovery.Plugins) *cobra.Command {
132
145
133
146
// TODO(chungers) -- we need to enforce and confirm the type of this.
134
147
// 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 )
136
149
137
150
log .Debug ("commit" , "plugin" , gp .Plugin , "address" , endpoint .Address , "err" , err , "spec" , spec )
138
151
@@ -165,26 +178,11 @@ func Command(plugins func() discovery.Plugins) *cobra.Command {
165
178
os .Exit (1 )
166
179
}
167
180
168
- specs , err := groupPlugin . InspectGroups ( )
181
+ out , err := getGlobalConfig ( groupPlugin , groupPluginName )
169
182
if err != nil {
170
183
return err
171
184
}
172
185
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
-
188
186
view , err := types .AnyValue (out )
189
187
if err != nil {
190
188
return err
@@ -202,7 +200,181 @@ func Command(plugins func() discovery.Plugins) *cobra.Command {
202
200
}
203
201
inspect .Flags ().AddFlagSet (templateFlags )
204
202
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 \n Commit? [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 )
206
321
207
322
return cmd
208
323
}
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