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

Commit d30f4bf

Browse files
author
David Chung
authored
[Experimental] - Max resource lifetime controller (#545)
Signed-off-by: David Chung <[email protected]>
1 parent 007114d commit d30f4bf

File tree

7 files changed

+433
-11
lines changed

7 files changed

+433
-11
lines changed

cmd/infrakit/main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import (
1919

2020
// TODO - deprecate these in favor of the dynamic commands (see above)
2121
//_ "github.com/docker/infrakit/cmd/infrakit/flavor"
22-
//_ "github.com/docker/infrakit/cmd/infrakit/instance"
2322
//_ "github.com/docker/infrakit/cmd/infrakit/group"
23+
//_ "github.com/docker/infrakit/cmd/infrakit/instance"
2424
//_ "github.com/docker/infrakit/cmd/infrakit/resource"
2525

2626
_ "github.com/docker/infrakit/cmd/infrakit/event"
@@ -32,6 +32,7 @@ import (
3232
_ "github.com/docker/infrakit/cmd/infrakit/remote"
3333
_ "github.com/docker/infrakit/cmd/infrakit/template"
3434
_ "github.com/docker/infrakit/cmd/infrakit/util"
35+
_ "github.com/docker/infrakit/cmd/infrakit/x"
3536
)
3637

3738
func init() {

cmd/infrakit/util/util.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ func Command(plugins func() discovery.Plugins) *cobra.Command {
2121
Short: "Utilties",
2222
}
2323

24-
util.AddCommand(muxCommand(plugins), fileServerCommand(plugins), trackCommand(plugins))
24+
util.AddCommand(
25+
muxCommand(plugins),
26+
fileServerCommand(plugins),
27+
trackCommand(plugins),
28+
)
2529

2630
return util
2731
}

cmd/infrakit/x/maxlife.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package x
2+
3+
import (
4+
"os"
5+
"strings"
6+
"time"
7+
8+
"github.com/docker/infrakit/pkg/discovery"
9+
"github.com/docker/infrakit/pkg/plugin"
10+
instance_rpc "github.com/docker/infrakit/pkg/rpc/instance"
11+
"github.com/docker/infrakit/pkg/spi/instance"
12+
"github.com/docker/infrakit/pkg/x/maxlife"
13+
"github.com/spf13/cobra"
14+
)
15+
16+
func maxlifeCommand(plugins func() discovery.Plugins) *cobra.Command {
17+
18+
cmd := &cobra.Command{
19+
Use: "maxlife <instance plugin name>...",
20+
Short: "Sets max life on the given instances",
21+
}
22+
23+
//name := cmd.Flags().String("name", "", "Name to use as name of this plugin")
24+
poll := cmd.Flags().DurationP("poll", "i", 10*time.Second, "Polling interval")
25+
maxlifeDuration := cmd.Flags().DurationP("maxlife", "m", 10*time.Minute, "Max lifetime of the resource")
26+
flagTags := cmd.Flags().StringSliceP("tag", "t", []string{}, "Tags to filter instance by")
27+
28+
cmd.RunE = func(c *cobra.Command, args []string) error {
29+
30+
if len(args) == 0 {
31+
cmd.Usage()
32+
os.Exit(-1)
33+
}
34+
35+
tags := toTags(*flagTags)
36+
37+
// Now we have a list of instance plugins to maxlife
38+
plugins, err := getInstancePlugins(plugins, args)
39+
if err != nil {
40+
return err
41+
}
42+
43+
// For each we start a goroutine to poll and kill instances
44+
controllers := []*maxlife.Controller{}
45+
46+
for name, plugin := range plugins {
47+
48+
controller := maxlife.NewController(name, plugin, *poll, *maxlifeDuration, tags)
49+
controller.Start()
50+
51+
controllers = append(controllers, controller)
52+
}
53+
54+
// TODO - publish events when we start taking down instances.
55+
done := make(chan struct{})
56+
57+
<-done
58+
return nil
59+
}
60+
61+
return cmd
62+
}
63+
64+
func ensureMaxlife(name string, plugin instance.Plugin, stop chan struct{}, poll, maxlife time.Duration,
65+
tags map[string]string, initialCount int) {
66+
}
67+
func getInstancePlugins(plugins func() discovery.Plugins, names []string) (map[string]instance.Plugin, error) {
68+
targets := map[string]instance.Plugin{}
69+
for _, target := range names {
70+
endpoint, err := plugins().Find(plugin.Name(target))
71+
if err != nil {
72+
return nil, err
73+
}
74+
if p, err := instance_rpc.NewClient(plugin.Name(target), endpoint.Address); err == nil {
75+
targets[target] = p
76+
} else {
77+
return nil, err
78+
}
79+
}
80+
return targets, nil
81+
}
82+
83+
func toTags(slice []string) map[string]string {
84+
tags := map[string]string{}
85+
86+
for _, tag := range slice {
87+
kv := strings.SplitN(tag, "=", 2)
88+
if len(kv) != 2 {
89+
log.Warn("bad format tag", "input", tag)
90+
continue
91+
}
92+
key := strings.TrimSpace(kv[0])
93+
val := strings.TrimSpace(kv[1])
94+
if key != "" && val != "" {
95+
tags[key] = val
96+
}
97+
}
98+
return tags
99+
}

cmd/infrakit/x/x.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package x
2+
3+
import (
4+
"github.com/docker/infrakit/cmd/infrakit/base"
5+
"github.com/docker/infrakit/pkg/discovery"
6+
logutil "github.com/docker/infrakit/pkg/log"
7+
"github.com/spf13/cobra"
8+
)
9+
10+
var log = logutil.New("module", "cli/x")
11+
12+
func init() {
13+
base.Register(Command)
14+
}
15+
16+
// Command is the head of this module
17+
func Command(plugins func() discovery.Plugins) *cobra.Command {
18+
19+
experimental := &cobra.Command{
20+
Use: "x",
21+
Short: "Experimental features",
22+
}
23+
24+
experimental.AddCommand(
25+
maxlifeCommand(plugins),
26+
)
27+
28+
return experimental
29+
}

pkg/types/link.go

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,42 @@ func init() {
2020
type Link struct {
2121
value string
2222
context string
23+
created time.Time
2324
}
2425

2526
// NewLink creates a link
2627
func NewLink() *Link {
2728
return &Link{
28-
value: randomAlphaNumericString(16),
29+
value: randomAlphaNumericString(16),
30+
created: time.Now(),
2931
}
3032
}
3133

32-
// NewLinkFromMap constructs a link from data in the map
34+
// Link related labels
35+
const (
36+
LinkLabel = "infrakit-link"
37+
LinkContextLabel = "infrakit-link-context"
38+
LinkCreatedLabel = "infrakit-link-created"
39+
)
40+
41+
// NewLinkFromMap constructs a link from data in the map. The link will have missing data
42+
// if the input does not contain the attribute labels.
3343
func NewLinkFromMap(m map[string]string) *Link {
3444
l := &Link{}
35-
if v, has := m["infrakit-link"]; has {
45+
if v, has := m[LinkLabel]; has {
3646
l.value = v
3747
}
3848

39-
if v, has := m["infrakit-link-context"]; has {
49+
if v, has := m[LinkContextLabel]; has {
4050
l.context = v
4151
}
52+
53+
if v, has := m[LinkCreatedLabel]; has {
54+
t, err := time.Parse(time.RFC3339, v)
55+
if err == nil {
56+
l.created = t
57+
}
58+
}
4259
return l
4360
}
4461

@@ -52,9 +69,14 @@ func (l Link) Value() string {
5269
return l.value
5370
}
5471

72+
// Created returns the creation time of the link
73+
func (l Link) Created() time.Time {
74+
return l.created
75+
}
76+
5577
// Label returns the label to look for the link
5678
func (l Link) Label() string {
57-
return "infrakit-link"
79+
return LinkLabel
5880
}
5981

6082
// Context returns the context of the link
@@ -80,8 +102,9 @@ func (l *Link) KVPairs() []string {
80102
// Map returns a representation that is easily converted to JSON or YAML
81103
func (l *Link) Map() map[string]string {
82104
return map[string]string{
83-
"infrakit-link": l.value,
84-
"infrakit-link-context": l.context,
105+
LinkLabel: l.value,
106+
LinkContextLabel: l.context,
107+
LinkCreatedLabel: l.created.Format(time.RFC3339),
85108
}
86109
}
87110

@@ -94,15 +117,15 @@ func (l *Link) WriteMap(target map[string]string) {
94117

95118
// InMap returns true if the link is contained in the map
96119
func (l *Link) InMap(m map[string]string) bool {
97-
c, has := m["infrakit-link-context"]
120+
c, has := m[LinkContextLabel]
98121
if !has {
99122
return false
100123
}
101124
if c != l.context {
102125
return false
103126
}
104127

105-
v, has := m["infrakit-link"]
128+
v, has := m[LinkLabel]
106129
if !has {
107130
return false
108131
}

0 commit comments

Comments
 (0)