Add support for Swarm IDs.

- Every container that gets created through Swarm gets a Swarm ID
  assigned (as a label).
- All API operations (start, stop, ...) can be performed by using either
  the container ID or the swarm ID.

Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
This commit is contained in:
Andrea Luzzardi 2015-05-07 00:34:18 -07:00
parent c4c07c97ac
commit abfe5e6f4c
4 changed files with 69 additions and 7 deletions

View File

@ -463,11 +463,16 @@ func (e *Engine) Container(IDOrName string) *Container {
} }
for _, container := range e.Containers() { for _, container := range e.Containers() {
// Match ID prefix. // Match Container ID prefix.
if strings.HasPrefix(container.Id, IDOrName) { if strings.HasPrefix(container.Id, IDOrName) {
return container return container
} }
// Match Swarm ID prefix.
if strings.HasPrefix(container.Config.SwarmID(), IDOrName) {
return container
}
// Match name, /name or engine/name. // Match name, /name or engine/name.
for _, name := range container.Names { for _, name := range container.Names {
if name == IDOrName || name == "/"+IDOrName || container.Engine.ID+name == IDOrName || container.Engine.Name+name == IDOrName { if name == IDOrName || name == "/"+IDOrName || container.Engine.ID+name == IDOrName || container.Engine.Name+name == IDOrName {

View File

@ -9,6 +9,7 @@ import (
"sync" "sync"
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/units" "github.com/docker/docker/pkg/units"
"github.com/docker/swarm/cluster" "github.com/docker/swarm/cluster"
"github.com/docker/swarm/discovery" "github.com/docker/swarm/discovery"
@ -80,16 +81,29 @@ func (c *Cluster) RegisterEventHandler(h cluster.EventHandler) error {
return nil return nil
} }
// Generate a globally (across the cluster) unique ID.
func (c *Cluster) generateUniqueID() string {
for {
id := stringid.GenerateRandomID()
if c.Container(id) == nil {
return id
}
}
}
// CreateContainer aka schedule a brand new container into the cluster. // CreateContainer aka schedule a brand new container into the cluster.
func (c *Cluster) CreateContainer(config *cluster.ContainerConfig, name string) (*cluster.Container, error) { func (c *Cluster) CreateContainer(config *cluster.ContainerConfig, name string) (*cluster.Container, error) {
c.scheduler.Lock() c.scheduler.Lock()
defer c.scheduler.Unlock() defer c.scheduler.Unlock()
// check new name whether avaliable // Ensure the name is avaliable
if cID := c.getIDFromName(name); cID != "" { if cID := c.getIDFromName(name); cID != "" {
return nil, fmt.Errorf("Conflict, The name %s is already assigned to %s. You have to delete (or rename) that container to be able to assign %s to a container again.", name, cID, name) return nil, fmt.Errorf("Conflict, The name %s is already assigned to %s. You have to delete (or rename) that container to be able to assign %s to a container again.", name, cID, name)
} }
// Associate a Swarm ID to the container we are creating.
config.SetSwarmID(c.generateUniqueID())
n, err := c.scheduler.SelectNodeForContainer(c.listNodes(), config) n, err := c.scheduler.SelectNodeForContainer(c.listNodes(), config)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -8,13 +8,14 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func createEngine(t *testing.T, ID string, containers ...dockerclient.Container) *cluster.Engine { func createEngine(t *testing.T, ID string, containers ...*cluster.Container) *cluster.Engine {
engine := cluster.NewEngine(ID, 0) engine := cluster.NewEngine(ID, 0)
engine.Name = ID engine.Name = ID
engine.ID = ID engine.ID = ID
for _, container := range containers { for _, container := range containers {
engine.AddContainer(&cluster.Container{Container: container, Engine: engine}) container.Engine = engine
engine.AddContainer(container)
} }
return engine return engine
@ -24,9 +25,16 @@ func TestContainerLookup(t *testing.T) {
c := &Cluster{ c := &Cluster{
engines: make(map[string]*cluster.Engine), engines: make(map[string]*cluster.Engine),
} }
container := dockerclient.Container{ container := &cluster.Container{
Id: "container-id", Container: dockerclient.Container{
Names: []string{"/container-name1", "/container-name2"}, Id: "container-id",
Names: []string{"/container-name1", "/container-name2"},
},
Config: cluster.BuildContainerConfig(dockerclient.ContainerConfig{
Labels: map[string]string{
"com.docker.swarm.id": "swarm-id",
},
}),
} }
n := createEngine(t, "test-engine", container) n := createEngine(t, "test-engine", container)
@ -45,4 +53,8 @@ func TestContainerLookup(t *testing.T) {
// Container engine/name matching. // Container engine/name matching.
assert.NotNil(t, c.Container("test-engine/container-name1")) assert.NotNil(t, c.Container("test-engine/container-name1"))
assert.NotNil(t, c.Container("test-engine/container-name2")) assert.NotNil(t, c.Container("test-engine/container-name2"))
// Swarm ID lookup.
assert.NotNil(t, c.Container("swarm-id"))
// Swarm ID prefix lookup.
assert.NotNil(t, c.Container("swarm-"))
} }

View File

@ -0,0 +1,31 @@
#!/usr/bin/env bats
load helpers
function teardown() {
swarm_manage_cleanup
stop_docker
}
@test "swarm id generation" {
start_docker_with_busybox 2
swarm_manage
# Create a dummy container just so we interfere with the tests.
# This one won't be used.
docker_swarm run -d busybox true
# Create a container and get its Swarm ID back.
id=$(docker_swarm run -d busybox true)
swarm_id=$(docker_swarm inspect -f '{{ index .Config.Labels "com.docker.swarm.id" }}' "$id")
# Make sure we got a valid Swarm ID.
[[ "${#swarm_id}" -eq 64 ]]
[[ "$id" != "$swarm_id" ]]
# API operations should work with Swarm IDs as well as Container IDs.
[[ $(docker_swarm inspect -f "{{ .Id }}" "$swarm_id") == "$id" ]]
# `docker ps` should be able to filter by Swarm ID using the label.
[[ $(docker_swarm ps -a -q --no-trunc --filter="label=com.docker.swarm.id=$swarm_id") == "$id" ]]
}