mirror of https://github.com/docker/docs.git
allow engine/name support in volumes
Signed-off-by: Victor Vieux <vieux@docker.com>
This commit is contained in:
parent
5cb6f218dd
commit
1225eddc79
|
|
@ -223,9 +223,15 @@ func getNetworks(c *context, w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// GET /volumes
|
||||
func getVolumes(c *context, w http.ResponseWriter, r *http.Request) {
|
||||
volumes := struct {
|
||||
Volumes []*cluster.Volume
|
||||
}{c.cluster.Volumes()}
|
||||
volumes := struct{ Volumes []*dockerclient.Volume }{}
|
||||
|
||||
for _, volume := range c.cluster.Volumes() {
|
||||
tmp := (*volume).Volume
|
||||
if tmp.Driver == "local" {
|
||||
tmp.Name = volume.Engine.Name + "/" + volume.Name
|
||||
}
|
||||
volumes.Volumes = append(volumes.Volumes, &tmp)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(volumes)
|
||||
|
|
@ -808,9 +814,9 @@ func proxyNetwork(c *context, w http.ResponseWriter, r *http.Request) {
|
|||
// Proxy a request to the right node
|
||||
func proxyVolume(c *context, w http.ResponseWriter, r *http.Request) {
|
||||
var name = mux.Vars(r)["volumename"]
|
||||
if volume := c.cluster.Volume(name); volume != nil {
|
||||
err := proxy(c.tlsConfig, volume.Engine.Addr, w, r)
|
||||
volume.Engine.CheckConnectionErr(err)
|
||||
if volume := c.cluster.Volumes().Get(name); volume != nil {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(volume)
|
||||
return
|
||||
}
|
||||
httpError(w, fmt.Sprintf("No such volume: %s", name), http.StatusNotFound)
|
||||
|
|
|
|||
|
|
@ -44,10 +44,7 @@ type Cluster interface {
|
|||
CreateVolume(request *dockerclient.VolumeCreateRequest) (*Volume, error)
|
||||
|
||||
// Return all volumes
|
||||
Volumes() []*Volume
|
||||
|
||||
// Return one volume from the cluster
|
||||
Volume(name string) *Volume
|
||||
Volumes() Volumes
|
||||
|
||||
// Remove volumes from the cluster
|
||||
RemoveVolumes(name string) (bool, error)
|
||||
|
|
|
|||
|
|
@ -857,10 +857,10 @@ func (e *Engine) Networks() Networks {
|
|||
}
|
||||
|
||||
// Volumes returns all the volumes in the engine
|
||||
func (e *Engine) Volumes() []*Volume {
|
||||
func (e *Engine) Volumes() Volumes {
|
||||
e.RLock()
|
||||
|
||||
volumes := make([]*Volume, 0, len(e.volumes))
|
||||
volumes := Volumes{}
|
||||
for _, volume := range e.volumes {
|
||||
volumes = append(volumes, volume)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -338,12 +338,7 @@ func (c *Cluster) Networks() cluster.Networks {
|
|||
}
|
||||
|
||||
// Volumes returns all the volumes in the cluster.
|
||||
func (c *Cluster) Volumes() []*cluster.Volume {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Volume returns the volume name in the cluster
|
||||
func (c *Cluster) Volume(name string) *cluster.Volume {
|
||||
func (c *Cluster) Volumes() cluster.Volumes {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ type Network struct {
|
|||
Engine *Engine
|
||||
}
|
||||
|
||||
// Networks represents a map of networks
|
||||
// Networks represents an array of networks
|
||||
type Networks []*Network
|
||||
|
||||
// Uniq returns all uniq networks
|
||||
|
|
|
|||
|
|
@ -441,6 +441,18 @@ func (c *Cluster) refreshNetworks() {
|
|||
wg.Wait()
|
||||
}
|
||||
|
||||
func (c *Cluster) refreshVolumes() {
|
||||
var wg sync.WaitGroup
|
||||
for _, e := range c.engines {
|
||||
wg.Add(1)
|
||||
go func(e *cluster.Engine) {
|
||||
e.RefreshVolumes()
|
||||
wg.Done()
|
||||
}(e)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// CreateNetwork creates a network in the cluster
|
||||
func (c *Cluster) CreateNetwork(request *dockerclient.NetworkCreate) (response *dockerclient.NetworkCreateResponse, err error) {
|
||||
var (
|
||||
|
|
@ -472,20 +484,45 @@ func (c *Cluster) CreateVolume(request *dockerclient.VolumeCreateRequest) (*clus
|
|||
wg sync.WaitGroup
|
||||
volume *cluster.Volume
|
||||
err error
|
||||
parts = strings.SplitN(request.Name, "/", 2)
|
||||
node = ""
|
||||
)
|
||||
|
||||
if request.Name == "" {
|
||||
request.Name = stringid.GenerateRandomID()
|
||||
} else if len(parts) == 2 {
|
||||
node = parts[0]
|
||||
request.Name = parts[1]
|
||||
}
|
||||
if node == "" {
|
||||
c.RLock()
|
||||
for _, e := range c.engines {
|
||||
wg.Add(1)
|
||||
|
||||
c.RLock()
|
||||
for _, e := range c.engines {
|
||||
wg.Add(1)
|
||||
go func(engine *cluster.Engine) {
|
||||
defer wg.Done()
|
||||
|
||||
go func(engine *cluster.Engine) {
|
||||
defer wg.Done()
|
||||
v, er := engine.CreateVolume(request)
|
||||
if v != nil {
|
||||
volume = v
|
||||
err = nil
|
||||
}
|
||||
if er != nil && volume == nil {
|
||||
err = er
|
||||
}
|
||||
}(e)
|
||||
}
|
||||
c.RUnlock()
|
||||
|
||||
v, er := engine.CreateVolume(request)
|
||||
wg.Wait()
|
||||
} else {
|
||||
config := cluster.BuildContainerConfig(dockerclient.ContainerConfig{Env: []string{"constraint:node==" + parts[0]}})
|
||||
nodes, err := c.scheduler.SelectNodesForContainer(c.listNodes(), config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if nodes != nil {
|
||||
v, er := c.engines[nodes[0].ID].CreateVolume(request)
|
||||
if v != nil {
|
||||
volume = v
|
||||
err = nil
|
||||
|
|
@ -493,11 +530,8 @@ func (c *Cluster) CreateVolume(request *dockerclient.VolumeCreateRequest) (*clus
|
|||
if er != nil && volume == nil {
|
||||
err = er
|
||||
}
|
||||
}(e)
|
||||
}
|
||||
}
|
||||
c.RUnlock()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return volume, err
|
||||
}
|
||||
|
|
@ -511,14 +545,12 @@ func (c *Cluster) RemoveVolumes(name string) (bool, error) {
|
|||
errs := []string{}
|
||||
var err error
|
||||
for _, e := range c.engines {
|
||||
for _, volume := range e.Volumes() {
|
||||
if volume.Name == name {
|
||||
if err := volume.Engine.RemoveVolume(name); err != nil {
|
||||
errs = append(errs, fmt.Sprintf("%s: %s", volume.Engine.Name, err.Error()))
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
if volume := e.Volumes().Get(name); volume != nil {
|
||||
if err := volume.Engine.RemoveVolume(volume.Name); err != nil {
|
||||
errs = append(errs, fmt.Sprintf("%s: %s", volume.Engine.Name, err.Error()))
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
|
|
@ -723,11 +755,11 @@ func (c *Cluster) Networks() cluster.Networks {
|
|||
}
|
||||
|
||||
// Volumes returns all the volumes in the cluster.
|
||||
func (c *Cluster) Volumes() []*cluster.Volume {
|
||||
func (c *Cluster) Volumes() cluster.Volumes {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
|
||||
out := []*cluster.Volume{}
|
||||
out := cluster.Volumes{}
|
||||
for _, e := range c.engines {
|
||||
out = append(out, e.Volumes()...)
|
||||
}
|
||||
|
|
@ -735,26 +767,6 @@ func (c *Cluster) Volumes() []*cluster.Volume {
|
|||
return out
|
||||
}
|
||||
|
||||
// Volume returns the volume name in the cluster
|
||||
func (c *Cluster) Volume(name string) *cluster.Volume {
|
||||
// Abort immediately if the name is empty.
|
||||
if len(name) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
|
||||
for _, e := range c.engines {
|
||||
for _, v := range e.Volumes() {
|
||||
if v.Name == name {
|
||||
return v
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// listNodes returns all validated engines in the cluster, excluding pendingEngines.
|
||||
func (c *Cluster) listNodes() []*node.Node {
|
||||
c.RLock()
|
||||
|
|
|
|||
|
|
@ -8,3 +8,42 @@ type Volume struct {
|
|||
|
||||
Engine *Engine
|
||||
}
|
||||
|
||||
// Volumes represents an array of volumes
|
||||
type Volumes []*Volume
|
||||
|
||||
// Get returns a volume using it's ID or Name
|
||||
func (volumes Volumes) Get(name string) *Volume {
|
||||
// Abort immediately if the name is empty.
|
||||
if len(name) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
candidates := []*Volume{}
|
||||
|
||||
// Match name, /name or engine/name.
|
||||
for _, volume := range volumes {
|
||||
if volume.Name == name || volume.Engine.ID+"/"+volume.Name == name || volume.Engine.Name+"/"+volume.Name == name {
|
||||
candidates = append(candidates, volume)
|
||||
}
|
||||
}
|
||||
|
||||
if size := len(candidates); size == 1 {
|
||||
return candidates[0]
|
||||
} else if size > 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Match name, /name or engine/name.
|
||||
for _, volume := range volumes {
|
||||
if volume.Name == "/"+name {
|
||||
return volume
|
||||
}
|
||||
}
|
||||
|
||||
if len(candidates) == 1 {
|
||||
return candidates[0]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,10 +32,11 @@ function teardown() {
|
|||
swarm_manage
|
||||
|
||||
# run
|
||||
docker_swarm run -d -v=/tmp busybox true
|
||||
docker_swarm run -d -v=/tmp -e constraint:node==node-0 busybox true
|
||||
|
||||
run docker_swarm volume ls -q
|
||||
[ "${#lines[@]}" -eq 1 ]
|
||||
[[ "${output}" == *"node-0/"* ]]
|
||||
|
||||
run docker_swarm volume inspect ${output}
|
||||
[ "${#lines[@]}" -eq 7 ]
|
||||
|
|
@ -56,6 +57,13 @@ function teardown() {
|
|||
docker_swarm run -d -v=/tmp busybox true
|
||||
run docker_swarm volume ls
|
||||
[ "${#lines[@]}" -eq 4 ]
|
||||
|
||||
run docker_swarm volume create --name=node-2/test_volume2
|
||||
[ "$status" -ne 0 ]
|
||||
|
||||
docker_swarm volume create --name=node-0/test_volume2
|
||||
run docker_swarm volume ls
|
||||
[ "${#lines[@]}" -eq 5 ]
|
||||
}
|
||||
|
||||
@test "docker volume rm" {
|
||||
|
|
|
|||
Loading…
Reference in New Issue