forked from docker-archive/classicswarm
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: michael.freund <[email protected]>
- Loading branch information
1 parent
e8cb44f
commit 0ccc958
Showing
6 changed files
with
311 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package filter | ||
|
||
import ( | ||
"errors" | ||
"github.com/docker/swarm/cluster" | ||
"github.com/docker/swarm/scheduler/node" | ||
"strconv" | ||
) | ||
|
||
var ( | ||
// ErrNoNodeWithFreeSlotsAvailable is exported | ||
ErrNoNodeWithFreeSlotsAvailable = errors.New("No node with enough open slots available in the cluster") | ||
) | ||
|
||
//SlotsFilter only schedules containers with open slots. | ||
type SlotsFilter struct { | ||
} | ||
|
||
// Name returns the name of the filter | ||
func (f *SlotsFilter) Name() string { | ||
return "containerslots" | ||
} | ||
|
||
// Filter is exported | ||
func (f *SlotsFilter) Filter(_ *cluster.ContainerConfig, nodes []*node.Node, _ bool) ([]*node.Node, error) { | ||
result := []*node.Node{} | ||
|
||
for _, node := range nodes { | ||
|
||
if slotsString, ok := node.Labels["containerslots"]; ok { | ||
slots, err := strconv.Atoi(slotsString) //if err => cannot cast to int, so ignore the label | ||
if err != nil || len(node.Containers) < slots { | ||
result = append(result, node) | ||
} | ||
} else { | ||
//no limit if label is missing | ||
result = append(result, node) | ||
} | ||
} | ||
|
||
if len(result) == 0 { | ||
return nil, ErrNoNodeWithFreeSlotsAvailable | ||
} | ||
|
||
return result, nil | ||
} | ||
|
||
// GetFilters returns just the info that this node failed, because there where no free slots | ||
func (f *SlotsFilter) GetFilters(config *cluster.ContainerConfig) ([]string, error) { | ||
return []string{"free slots"}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
package filter | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/docker/engine-api/types" | ||
"github.com/docker/swarm/cluster" | ||
"github.com/docker/swarm/scheduler/node" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
var labelsWithSlots = make(map[string]string) | ||
var labelsWithoutSlots = make(map[string]string) | ||
var labelsWithStringSlot = make(map[string]string) | ||
|
||
func testFixturesAllFreeNode() []*node.Node { | ||
return []*node.Node{ | ||
{ | ||
ID: "node-0-id", | ||
Name: "node-0-name", | ||
Labels: labelsWithSlots, | ||
Containers: []*cluster.Container{ | ||
{Container: types.Container{}}, | ||
}, | ||
}, | ||
{ | ||
ID: "node-1-id", | ||
Name: "node-1-name", | ||
Labels: labelsWithSlots, | ||
Containers: []*cluster.Container{}, | ||
}, | ||
} | ||
} | ||
|
||
func testFixturesPartlyFreeNode() []*node.Node { | ||
return []*node.Node{ | ||
{ | ||
ID: "node-0-id", | ||
Name: "node-0-name", | ||
Labels: labelsWithSlots, | ||
Containers: []*cluster.Container{ | ||
{Container: types.Container{}}, | ||
{Container: types.Container{}}, | ||
{Container: types.Container{}}, | ||
}, | ||
}, | ||
{ | ||
ID: "node-1-id", | ||
Name: "node-1-name", | ||
Labels: labelsWithSlots, | ||
Containers: []*cluster.Container{}, | ||
}, | ||
} | ||
} | ||
|
||
func testFixturesAllNoLabelNode() []*node.Node { | ||
return []*node.Node{ | ||
{ | ||
ID: "node-0-id", | ||
Name: "node-0-name", | ||
Labels: labelsWithoutSlots, | ||
Containers: []*cluster.Container{ | ||
{Container: types.Container{}}, | ||
{Container: types.Container{}}, | ||
{Container: types.Container{}}, | ||
}, | ||
}, | ||
|
||
{ | ||
ID: "node-1-id", | ||
Name: "node-1-name", | ||
Labels: labelsWithoutSlots, | ||
Containers: []*cluster.Container{}, | ||
}, | ||
} | ||
} | ||
|
||
func testFixturesNoFreeNode() []*node.Node { | ||
return []*node.Node{ | ||
{ | ||
ID: "node-0-id", | ||
Name: "node-0-name", | ||
Labels: labelsWithSlots, | ||
Containers: []*cluster.Container{ | ||
{Container: types.Container{}}, | ||
{Container: types.Container{}}, | ||
{Container: types.Container{}}, | ||
}, | ||
}, | ||
|
||
{ | ||
ID: "node-1-id", | ||
Name: "node-1-name", | ||
Labels: labelsWithSlots, | ||
Containers: []*cluster.Container{ | ||
{Container: types.Container{}}, | ||
{Container: types.Container{}}, | ||
{Container: types.Container{}}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func testFixturesNoFreeNodeButStringLabel() []*node.Node { | ||
return []*node.Node{ | ||
{ | ||
ID: "node-0-id", | ||
Name: "node-0-name", | ||
Labels: labelsWithSlots, | ||
Containers: []*cluster.Container{ | ||
{Container: types.Container{}}, | ||
{Container: types.Container{}}, | ||
{Container: types.Container{}}, | ||
}, | ||
}, | ||
|
||
{ | ||
ID: "node-1-id", | ||
Name: "node-1-name", | ||
Labels: labelsWithStringSlot, | ||
Containers: []*cluster.Container{ | ||
{Container: types.Container{}}, | ||
{Container: types.Container{}}, | ||
{Container: types.Container{}}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func TestSlotsFilter(t *testing.T) { | ||
|
||
labelsWithSlots["containerslots"] = "3" | ||
labelsWithStringSlot["containerslots"] = "foo" | ||
|
||
var ( | ||
f = SlotsFilter{} | ||
nodesAllFree = testFixturesAllFreeNode() | ||
nodesPartlyFree = testFixturesPartlyFreeNode() | ||
nodesAllNoLabel = testFixturesAllNoLabelNode() | ||
nodesNoFree = testFixturesNoFreeNode() | ||
nodesNoFreeButStringLabel = testFixturesNoFreeNodeButStringLabel() | ||
result []*node.Node | ||
err error | ||
) | ||
|
||
result, err = f.Filter(&cluster.ContainerConfig{}, nodesAllFree, true) | ||
assert.NoError(t, err) | ||
assert.Equal(t, result, nodesAllFree) | ||
|
||
result, err = f.Filter(&cluster.ContainerConfig{}, nodesPartlyFree, true) | ||
assert.NoError(t, err) | ||
assert.Len(t, result, 1) | ||
assert.Equal(t, result[0], nodesPartlyFree[1]) | ||
|
||
result, err = f.Filter(&cluster.ContainerConfig{}, nodesAllNoLabel, true) | ||
assert.NoError(t, err) | ||
assert.Equal(t, result, nodesAllNoLabel) | ||
|
||
result, err = f.Filter(&cluster.ContainerConfig{}, nodesNoFree, true) | ||
assert.Equal(t, err, ErrNoNodeWithFreeSlotsAvailable) | ||
assert.Nil(t, result) | ||
|
||
result, err = f.Filter(&cluster.ContainerConfig{}, nodesNoFreeButStringLabel, true) | ||
assert.NoError(t, err) | ||
assert.Len(t, result, 1) | ||
assert.Equal(t, result[0], nodesNoFreeButStringLabel[1]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
#!/usr/bin/env bats | ||
|
||
load helpers | ||
|
||
function teardown() { | ||
swarm_manage_cleanup | ||
stop_docker | ||
} | ||
|
||
@test "containerslots filter" { | ||
start_docker_with_busybox 2 --label containerslots=2 | ||
swarm_manage | ||
|
||
# Use busybox to save image pulling time for integration test. | ||
# Running the first 4 containers, it should be fine. | ||
run docker_swarm run -d -t busybox sh | ||
[ "$status" -eq 0 ] | ||
run docker_swarm run -d -t busybox sh | ||
[ "$status" -eq 0 ] | ||
run docker_swarm run -d -t busybox sh | ||
[ "$status" -eq 0 ] | ||
run docker_swarm run -d -t busybox sh | ||
[ "$status" -eq 0 ] | ||
|
||
# When trying to start the 5th one, it should be error finding a node with free slots. | ||
run docker_swarm run -d -t busybox sh | ||
[ "$status" -ne 0 ] | ||
[[ "${lines[0]}" == *"Unable to find a node that satisfies the following conditions"* ]] | ||
[[ "${lines[1]}" == *"free slots"* ]] | ||
|
||
# And the number of running containers should be still 4. | ||
run docker_swarm ps | ||
[ "${#lines[@]}" -eq 5 ] | ||
} | ||
|
||
@test "containerslots without existing label" { | ||
start_docker_with_busybox 2 | ||
swarm_manage | ||
|
||
# Use busybox to save image pulling time for integration test. | ||
# Running more than 5 containers, it should be fine. | ||
run docker_swarm run -d -t busybox sh | ||
[ "$status" -eq 0 ] | ||
run docker_swarm run -d -t busybox sh | ||
[ "$status" -eq 0 ] | ||
run docker_swarm run -d -t busybox sh | ||
[ "$status" -eq 0 ] | ||
run docker_swarm run -d -t busybox sh | ||
[ "$status" -eq 0 ] | ||
run docker_swarm run -d -t busybox sh | ||
[ "$status" -eq 0 ] | ||
|
||
# And the number of running containers should be 5. | ||
run docker_swarm ps | ||
[ "${#lines[@]}" -eq 6 ] | ||
} | ||
|
||
@test "containerslots with invalid label" { | ||
start_docker_with_busybox 2 --label containerslots="foo" | ||
swarm_manage | ||
|
||
# Use busybox to save image pulling time for integration test. | ||
# Running more than 5 containers, it should be fine. | ||
run docker_swarm run -d -t busybox sh | ||
[ "$status" -eq 0 ] | ||
run docker_swarm run -d -t busybox sh | ||
[ "$status" -eq 0 ] | ||
run docker_swarm run -d -t busybox sh | ||
[ "$status" -eq 0 ] | ||
run docker_swarm run -d -t busybox sh | ||
[ "$status" -eq 0 ] | ||
run docker_swarm run -d -t busybox sh | ||
[ "$status" -eq 0 ] | ||
|
||
# And the number of running containers should be 5. | ||
run docker_swarm ps | ||
[ "${#lines[@]}" -eq 6 ] | ||
} |