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

Commit 5c792c7

Browse files
author
David Chung
authored
Refactor to use a common template runtime package (#725)
Signed-off-by: David Chung <[email protected]>
1 parent 45d70d7 commit 5c792c7

File tree

15 files changed

+459
-217
lines changed

15 files changed

+459
-217
lines changed

docs/plugin/metadata/vars/README.md

Lines changed: 119 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
Vars Plugin
22
===========
33

4-
Design
5-
======
4+
## Design
65

76
The `vars` plugin implements the [`metadata.Updatable`](../pkg/spi/metadata) SPI. It supports
87

@@ -131,7 +130,7 @@ Usage:
131130
Available Commands:
132131
cat Get metadata entry by path
133132
change Update metadata where args are key=value pairs and keys are within namespace of the plugin.
134-
ls List metadata
133+
vars List metadata
135134
```
136135

137136
### Listing, Reading
@@ -325,6 +324,123 @@ $ infrakit vars cat this/is/a/new/struct/message
325324
i am here
326325
```
327326

327+
## Template integration
328+
329+
As mentioned earlier, metadata operations are integrated with templates so you
330+
can write templates that also access the variables stored in the vars plugin.
331+
332+
As an example:
333+
334+
```shell
335+
$infrakit plugin start vars # starts up only the vars
336+
```
337+
338+
In another shell:
339+
340+
```shell
341+
$ infrakit vars change
342+
Proposing 0 changes, hash=c53f4ebe9b2a50bc2b52fd88a5d503e1
343+
{}
344+
```
345+
346+
Currently there's no data stored.
347+
348+
Adding some values:
349+
350+
```shell
351+
$ infrakit vars change cluster/name=foo cluster/workers/size=10 -c
352+
Committing 2 changes, hash=ad861ded7a0742f9662c2b78354c89f6
353+
{
354+
"cluster": {
355+
"name": "foo",
356+
"workers": {
357+
"size": 10
358+
}
359+
}
360+
}
361+
```
362+
363+
Now querying:
364+
365+
```shell
366+
$ infrakit vars vars -al
367+
total 2:
368+
cluster/name
369+
cluster/workers/size
370+
$ infrakit vars cat cluster/workers/size
371+
10
372+
```
373+
Or use template to read.
374+
375+
```shell
376+
$ infrakit template -f 'str://{{ metadata `vars/cluster/workers/size`}}'
377+
10
378+
```
379+
380+
Using template to update:
381+
382+
```shell
383+
$ infrakit template -f 'str://{{ metadata `vars/cluster/workers/size` 1000 }}'
384+
~/project3/src/github.com/docker/infrakit$ infrakit vars change
385+
Proposing 0 changes, hash=8aff842d0f19e571e5c1e5810d562bb1
386+
{
387+
"cluster": {
388+
"name": "foo",
389+
"workers": {
390+
"size": 1000
391+
}
392+
}
393+
}
394+
$ infrakit vars cat cluster/workers/size
395+
1000
396+
```
397+
398+
Sometimes, you want to have a single namespace between metadata and template
399+
variables to simplify writing templates. The `var` template function, in
400+
correct contexts, can attempt to retrieve the value at the given path via accessing
401+
the path as though it's hosted in a metadata plugin, if the path cannot be resolved
402+
to an in-scope template variable:
403+
404+
```shell
405+
$ infrakit template 'str://{{ var `vars/cluster/workers/size`}}'
406+
1000
407+
```
408+
which is the same as
409+
410+
```shell
411+
$ infrakit template 'str://{{ metadata `vars/cluster/workers/size`}}'
412+
1000
413+
```
414+
415+
This works even when a template is multi-pass: if a path cannot be resolved
416+
from in-scope template variables, then metadata plugins are tested. Of course,
417+
the path has to also make sense in that the path can resolve to a running metadata
418+
plugin.
419+
420+
If somewhere else in your template, a `var` function is used to set a value and
421+
that value comes into scope of the template, that value will takes precedence:
422+
423+
```shell
424+
$ infrakit template 'str://{{ var `vars/cluster/workers/size` 4000 }}{{ var `vars/cluster/workers/size`}}'
425+
4000
426+
```
427+
This should not be surprising, as we are setting the `vars/cluster/workers/size`
428+
template variable to `4000`. The next read will return that value and not the
429+
metadata stored in vars:
430+
431+
```shell
432+
$ infrakit template 'str://{{ var `vars/cluster/workers/size`}}'
433+
1000
434+
```
435+
436+
The value is back to 1000 because the second command line invocation is a
437+
totally different template context (ie a different shell process altogether).
438+
This makes it possible to implement a user override, while the backing
439+
metadata can be loaded from a JSON serving as default values.
440+
This also means that mutation of the value at a given path must be performed
441+
explicitly via the `metadata` template function (or via the `change -c` CLI) to
442+
affect durability across multiple template evaluations.
443+
328444
## TODO - Durability of Changes
329445

330446
The metadata / updatable plugin is one of the key patterns provided by Infrakit. The base implementation

pkg/cli/context.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"strings"
1111

1212
"github.com/docker/infrakit/pkg/discovery"
13+
runtime "github.com/docker/infrakit/pkg/run/template"
1314
"github.com/docker/infrakit/pkg/template"
1415
"github.com/spf13/cobra"
1516
)
@@ -461,7 +462,7 @@ func (c *Context) BuildFlags() (err error) {
461462
return
462463
}
463464
t.SetOptions(c.options)
464-
_, err = configureTemplate(t, c.plugins).Render(c)
465+
_, err = runtime.StdFunctions(t, c.plugins).Render(c)
465466
return
466467
}
467468

@@ -484,7 +485,7 @@ func (c *Context) Execute() (err error) {
484485
// Process the input, render the template
485486
t.SetOptions(opt)
486487

487-
script, err := configureTemplate(t, c.plugins).Render(c)
488+
script, err := runtime.StdFunctions(t, c.plugins).Render(c)
488489
if err != nil {
489490
return err
490491
}

pkg/cli/services.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"strings"
1010

1111
"github.com/docker/infrakit/pkg/discovery"
12+
runtime "github.com/docker/infrakit/pkg/run/template"
1213
"github.com/docker/infrakit/pkg/template"
1314
"github.com/ghodss/yaml"
1415
"github.com/spf13/pflag"
@@ -197,7 +198,7 @@ func templateProcessor(plugins func() discovery.Plugins) (*pflag.FlagSet, ToJSON
197198
}
198199
}
199200

200-
configureTemplate(engine, plugins)
201+
runtime.StdFunctions(engine, plugins)
201202

202203
contextObject := (interface{})(nil)
203204
if len(ctx) == 1 {

pkg/cli/template.go

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

pkg/cli/v0/group/describe.go

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
package group
22

33
import (
4-
"fmt"
5-
"io"
64
"os"
7-
"sort"
8-
"strings"
95

106
"github.com/docker/infrakit/pkg/cli"
7+
"github.com/docker/infrakit/pkg/cli/v0/instance"
118
"github.com/docker/infrakit/pkg/plugin"
129
"github.com/docker/infrakit/pkg/spi/group"
1310
"github.com/spf13/cobra"
@@ -21,7 +18,10 @@ func Describe(name string, services *cli.Services) *cobra.Command {
2118
Short: "Describe a group. Returns a list of members",
2219
}
2320

24-
quiet := describe.Flags().BoolP("quiet", "q", false, "Print rows without column headers")
21+
view := instance.View{}
22+
describe.Flags().AddFlagSet(services.OutputFlags)
23+
describe.Flags().AddFlagSet(view.FlagSet())
24+
2525
describe.RunE = func(cmd *cobra.Command, args []string) error {
2626

2727
pluginName := plugin.Name(name)
@@ -30,9 +30,15 @@ func Describe(name string, services *cli.Services) *cobra.Command {
3030
if len(args) < 1 {
3131
cmd.Usage()
3232
os.Exit(1)
33-
} else {
34-
gid = args[0]
3533
}
34+
gid = args[0]
35+
args = args[1:]
36+
}
37+
38+
// get renderers first before costly rpc
39+
renderer, err := view.Renderer(view.DefaultMatcher(args))
40+
if err != nil {
41+
return err
3642
}
3743

3844
groupPlugin, err := LoadPlugin(services.Plugins(), name)
@@ -43,33 +49,17 @@ func Describe(name string, services *cli.Services) *cobra.Command {
4349

4450
groupID := group.ID(gid)
4551

52+
// TODO - here we are getting the properties back because
53+
// in pkg/plugin/group/scaledGroup.List we are calling the instance
54+
// plugin.Describe with 'true'. We need to change the group SPI
55+
// to allow control of this and taking in view filter, selectors
56+
// to execute on the server side.
4657
desc, err := groupPlugin.DescribeGroup(groupID)
4758
if err != nil {
4859
return err
4960
}
5061

51-
return services.Output(os.Stdout, desc,
52-
func(io.Writer, interface{}) error {
53-
if !*quiet {
54-
fmt.Printf("%-30s\t%-30s\t%-s\n", "ID", "LOGICAL", "TAGS")
55-
}
56-
for _, d := range desc.Instances {
57-
logical := " - "
58-
if d.LogicalID != nil {
59-
logical = string(*d.LogicalID)
60-
}
61-
62-
printTags := []string{}
63-
for k, v := range d.Tags {
64-
printTags = append(printTags, fmt.Sprintf("%s=%s", k, v))
65-
}
66-
sort.Strings(printTags)
67-
68-
fmt.Printf("%-30s\t%-30s\t%-s\n", d.ID, logical, strings.Join(printTags, ","))
69-
}
70-
return nil
71-
})
62+
return services.Output(os.Stdout, desc.Instances, renderer)
7263
}
73-
describe.Flags().AddFlagSet(services.OutputFlags)
7464
return describe
7565
}

0 commit comments

Comments
 (0)