This repository has been archived by the owner on Jan 21, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 262
/
flavor.go
172 lines (136 loc) · 4.24 KB
/
flavor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package combo // import "github.com/docker/infrakit/pkg/plugin/flavor/combo"
import (
"errors"
"strings"
group_controller "github.com/docker/infrakit/pkg/controller/group"
group_types "github.com/docker/infrakit/pkg/controller/group/types"
"github.com/docker/infrakit/pkg/spi/flavor"
"github.com/docker/infrakit/pkg/spi/group"
"github.com/docker/infrakit/pkg/spi/instance"
"github.com/docker/infrakit/pkg/types"
)
// Spec icrs the model of the plugin Properties.
type Spec []group_types.FlavorPlugin
// Options is the static properties required for starting things up
type Options struct {
}
// DefaultOptions has the default values for options
var DefaultOptions = Options{}
// NewPlugin creates a Flavor Combo plugin that chains multiple flavors in a sequence. Each flavor
func NewPlugin(flavorPlugins group_controller.FlavorPluginLookup, options Options) flavor.Plugin {
return flavorCombo{flavorPlugins: flavorPlugins}
}
type flavorCombo struct {
flavorPlugins group_controller.FlavorPluginLookup
}
func (f flavorCombo) Validate(flavorProperties *types.Any, allocation group.AllocationMethod) error {
s := Spec{}
return flavorProperties.Decode(&s)
}
func (f flavorCombo) Healthy(flavorProperties *types.Any, inst instance.Description) (flavor.Health, error) {
// The overall health of the flavor combination is taken as the 'lowest common demoninator' of the configured
// flavors. Only flavor.Healthy is reported if all flavors report flavor.Healthy. flavor.Unhealthy or
// flavor.UnknownHealth is returned as soon as any Flavor reports that value.
s := Spec{}
if err := flavorProperties.Decode(&s); err != nil {
return flavor.Unknown, err
}
for _, pluginSpec := range s {
plugin, err := f.flavorPlugins(pluginSpec.Plugin)
if err != nil {
return flavor.Unknown, err
}
health, err := plugin.Healthy(pluginSpec.Properties, inst)
if err != nil || health != flavor.Healthy {
return health, err
}
}
return flavor.Healthy, nil
}
func (f flavorCombo) Drain(flavorProperties *types.Any, inst instance.Description) error {
// Draining is attempted on all flavors regardless of errors encountered. All errors encountered are combined
// and returned.
s := Spec{}
if err := flavorProperties.Decode(&s); err != nil {
return err
}
errs := []string{}
for _, pluginSpec := range s {
plugin, err := f.flavorPlugins(pluginSpec.Plugin)
if err != nil {
errs = append(errs, err.Error())
}
if err := plugin.Drain(pluginSpec.Properties, inst); err != nil {
errs = append(errs, err.Error())
}
}
if len(errs) == 0 {
return nil
}
return errors.New(strings.Join(errs, ", "))
}
func cloneSpec(spec instance.Spec) instance.Spec {
tags := map[string]string{}
for k, v := range spec.Tags {
tags[k] = v
}
var logicalID *instance.LogicalID
if spec.LogicalID != nil {
idCopy := *spec.LogicalID
logicalID = &idCopy
}
attachments := []instance.Attachment{}
for _, v := range spec.Attachments {
attachments = append(attachments, v)
}
return instance.Spec{
Properties: spec.Properties,
Tags: tags,
Init: spec.Init,
LogicalID: logicalID,
Attachments: attachments,
}
}
func mergeSpecs(initial instance.Spec, specs []instance.Spec) (instance.Spec, error) {
result := cloneSpec(initial)
for _, spec := range specs {
for k, v := range spec.Tags {
result.Tags[k] = v
}
if spec.Init != "" {
if result.Init != "" {
result.Init += "\n"
}
result.Init += spec.Init
}
for _, v := range spec.Attachments {
result.Attachments = append(result.Attachments, v)
}
}
return result, nil
}
func (f flavorCombo) Prepare(flavor *types.Any,
inst instance.Spec,
allocation group.AllocationMethod,
index group.Index) (instance.Spec, error) {
combo := Spec{}
err := flavor.Decode(&combo)
if err != nil {
return inst, err
}
specs := []instance.Spec{}
for _, pluginSpec := range combo {
// Copy the instance spec to prevent Flavor plugins from interfering with each other.
clone := cloneSpec(inst)
plugin, err := f.flavorPlugins(pluginSpec.Plugin)
if err != nil {
return inst, err
}
flavorOutput, err := plugin.Prepare(pluginSpec.Properties, clone, allocation, index)
if err != nil {
return inst, err
}
specs = append(specs, flavorOutput)
}
return mergeSpecs(inst, specs)
}