forked from moby/swarmkit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
filter.go
131 lines (111 loc) · 3.71 KB
/
filter.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
package scheduler
import "github.com/docker/swarmkit/api"
// Filter checks whether the given task can run on the given node.
// A filter may only operate
type Filter interface {
// SetTask returns true when the filter is enabled for a given task
// and assigns the task to the filter. It returns false if the filter
// isn't applicable to this task. For instance, a constraints filter
// would return `false` if the task doesn't contain any constraints.
SetTask(*api.Task) bool
// Check returns true if the task assigned by SetTask can be scheduled
// into the given node. This function should not be called if SetTask
// returned false.
Check(*NodeInfo) bool
}
// ReadyFilter checks that the node is ready to schedule tasks.
type ReadyFilter struct {
}
// SetTask returns true when the filter is enabled for a given task.
func (f *ReadyFilter) SetTask(_ *api.Task) bool {
return true
}
// Check returns true if the task can be scheduled into the given node.
func (f *ReadyFilter) Check(n *NodeInfo) bool {
return n.Status.State == api.NodeStatus_READY &&
n.Spec.Availability == api.NodeAvailabilityActive
}
// ResourceFilter checks that the node has enough resources available to run
// the task.
type ResourceFilter struct {
reservations *api.Resources
}
// SetTask returns true when the filter is enabled for a given task.
func (f *ResourceFilter) SetTask(t *api.Task) bool {
r := t.Spec.Resources
if r == nil || r.Reservations == nil {
return false
}
if r.Reservations.NanoCPUs == 0 && r.Reservations.MemoryBytes == 0 {
return false
}
f.reservations = r.Reservations
return true
}
// Check returns true if the task can be scheduled into the given node.
func (f *ResourceFilter) Check(n *NodeInfo) bool {
if f.reservations.NanoCPUs > n.AvailableResources.NanoCPUs {
return false
}
if f.reservations.MemoryBytes > n.AvailableResources.MemoryBytes {
return false
}
return true
}
// PluginFilter checks that the node has a specific volume plugin installed
type PluginFilter struct {
t *api.Task
}
// SetTask returns true when the filter is enabled for a given task.
func (f *PluginFilter) SetTask(t *api.Task) bool {
c := t.Spec.GetContainer()
var volumeTemplates bool
if c != nil {
for _, mount := range c.Mounts {
if mount.Type == api.MountTypeVolume &&
mount.VolumeOptions != nil &&
mount.VolumeOptions.DriverConfig != nil &&
mount.VolumeOptions.DriverConfig.Name != "" &&
mount.VolumeOptions.DriverConfig.Name != "local" {
volumeTemplates = true
}
}
}
if (c != nil && volumeTemplates) || len(t.Networks) > 0 {
f.t = t
return true
}
return false
}
// Check returns true if the task can be scheduled into the given node.
// TODO(amitshukla): investigate storing Plugins as a map so it can be easily probed
func (f *PluginFilter) Check(n *NodeInfo) bool {
// Get list of plugins on the node
nodePlugins := n.Description.Engine.Plugins
// Check if all volume plugins required by task are installed on node
container := f.t.Spec.GetContainer()
if container != nil {
for _, mount := range container.Mounts {
if mount.VolumeOptions != nil && mount.VolumeOptions.DriverConfig != nil {
if !f.pluginExistsOnNode("Volume", mount.VolumeOptions.DriverConfig.Name, nodePlugins) {
return false
}
}
}
}
// Check if all network plugins required by task are installed on node
for _, tn := range f.t.Networks {
if !f.pluginExistsOnNode("Network", tn.Network.DriverState.Name, nodePlugins) {
return false
}
}
return true
}
func (f *PluginFilter) pluginExistsOnNode(pluginType string, pluginName string, nodePlugins []api.PluginDescription) bool {
for _, np := range nodePlugins {
if pluginType == np.Type && pluginName == np.Name {
return true
}
}
return false
}