mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #17390 from sanimej/libn
Vendor in libnetwork changes to support container rename
This commit is contained in:
commit
64854277f8
8 changed files with 173 additions and 25 deletions
|
@ -1,18 +1,28 @@
|
||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
derr "github.com/docker/docker/errors"
|
derr "github.com/docker/docker/errors"
|
||||||
|
"github.com/docker/libnetwork"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerRename changes the name of a container, using the oldName
|
// ContainerRename changes the name of a container, using the oldName
|
||||||
// to find the container. An error is returned if newName is already
|
// to find the container. An error is returned if newName is already
|
||||||
// reserved.
|
// reserved.
|
||||||
func (daemon *Daemon) ContainerRename(oldName, newName string) error {
|
func (daemon *Daemon) ContainerRename(oldName, newName string) error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
sid string
|
||||||
|
sb libnetwork.Sandbox
|
||||||
|
container *Container
|
||||||
|
)
|
||||||
|
|
||||||
if oldName == "" || newName == "" {
|
if oldName == "" || newName == "" {
|
||||||
return derr.ErrorCodeEmptyRename
|
return derr.ErrorCodeEmptyRename
|
||||||
}
|
}
|
||||||
|
|
||||||
container, err := daemon.Get(oldName)
|
container, err = daemon.Get(oldName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -27,19 +37,44 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
|
||||||
|
|
||||||
container.Name = newName
|
container.Name = newName
|
||||||
|
|
||||||
undo := func() {
|
defer func() {
|
||||||
container.Name = oldName
|
if err != nil {
|
||||||
daemon.reserveName(container.ID, oldName)
|
container.Name = oldName
|
||||||
daemon.containerGraphDB.Delete(newName)
|
daemon.reserveName(container.ID, oldName)
|
||||||
}
|
daemon.containerGraphDB.Delete(newName)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if err := daemon.containerGraphDB.Delete(oldName); err != nil {
|
if err = daemon.containerGraphDB.Delete(oldName); err != nil {
|
||||||
undo()
|
|
||||||
return derr.ErrorCodeRenameDelete.WithArgs(oldName, err)
|
return derr.ErrorCodeRenameDelete.WithArgs(oldName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := container.toDisk(); err != nil {
|
if err = container.toDisk(); err != nil {
|
||||||
undo()
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !container.Running {
|
||||||
|
container.logEvent("rename")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
container.Name = oldName
|
||||||
|
if e := container.toDisk(); e != nil {
|
||||||
|
logrus.Errorf("%s: Failed in writing to Disk on rename failure: %v", container.ID, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
sid = container.NetworkSettings.SandboxID
|
||||||
|
sb, err = daemon.netController.SandboxByID(sid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sb.Rename(strings.TrimPrefix(container.Name, "/"))
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ clone git github.com/vdemeester/shakers 3c10293ce22b900c27acad7b28656196fcc2f73b
|
||||||
clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git
|
clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git
|
||||||
|
|
||||||
#get libnetwork packages
|
#get libnetwork packages
|
||||||
clone git github.com/docker/libnetwork c92c21bca42a3581fd108d3222848faa16372249
|
clone git github.com/docker/libnetwork abc0807d72e309f53155ec4f6374a77fd6613849
|
||||||
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
||||||
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
||||||
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
|
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
|
||||||
|
|
|
@ -38,6 +38,27 @@ func (s *DockerSuite) TestRenameRunningContainer(c *check.C) {
|
||||||
c.Assert(name, checker.Equals, "/"+newName, check.Commentf("Failed to rename container %s", name))
|
c.Assert(name, checker.Equals, "/"+newName, check.Commentf("Failed to rename container %s", name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestRenameRunningContainerAndReuse(c *check.C) {
|
||||||
|
testRequires(c, DaemonIsLinux)
|
||||||
|
out, _ := dockerCmd(c, "run", "--name", "first_name", "-d", "busybox", "top")
|
||||||
|
c.Assert(waitRun("first_name"), check.IsNil)
|
||||||
|
|
||||||
|
newName := "new_name"
|
||||||
|
ContainerID := strings.TrimSpace(out)
|
||||||
|
dockerCmd(c, "rename", "first_name", newName)
|
||||||
|
|
||||||
|
name, err := inspectField(ContainerID, "Name")
|
||||||
|
c.Assert(err, checker.IsNil, check.Commentf("Failed to rename container %s", name))
|
||||||
|
c.Assert(name, checker.Equals, "/"+newName, check.Commentf("Failed to rename container"))
|
||||||
|
|
||||||
|
out, _ = dockerCmd(c, "run", "--name", "first_name", "-d", "busybox", "top")
|
||||||
|
c.Assert(waitRun("first_name"), check.IsNil)
|
||||||
|
newContainerID := strings.TrimSpace(out)
|
||||||
|
name, err = inspectField(newContainerID, "Name")
|
||||||
|
c.Assert(err, checker.IsNil, check.Commentf("Failed to reuse container name"))
|
||||||
|
c.Assert(name, checker.Equals, "/first_name", check.Commentf("Failed to reuse container name"))
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DockerSuite) TestRenameCheckNames(c *check.C) {
|
func (s *DockerSuite) TestRenameCheckNames(c *check.C) {
|
||||||
testRequires(c, DaemonIsLinux)
|
testRequires(c, DaemonIsLinux)
|
||||||
dockerCmd(c, "run", "--name", "first_name", "-d", "busybox", "sh")
|
dockerCmd(c, "run", "--name", "first_name", "-d", "busybox", "sh")
|
||||||
|
|
|
@ -143,6 +143,7 @@ type controller struct {
|
||||||
watchCh chan *endpoint
|
watchCh chan *endpoint
|
||||||
unWatchCh chan *endpoint
|
unWatchCh chan *endpoint
|
||||||
svcDb map[string]svcMap
|
svcDb map[string]svcMap
|
||||||
|
nmap map[string]*netWatch
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -431,6 +431,51 @@ func (ep *endpoint) sbJoin(sbox Sandbox, options ...EndpointOption) error {
|
||||||
return sb.clearDefaultGW()
|
return sb.clearDefaultGW()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ep *endpoint) rename(name string) error {
|
||||||
|
var err error
|
||||||
|
n := ep.getNetwork()
|
||||||
|
if n == nil {
|
||||||
|
return fmt.Errorf("network not connected for ep %q", ep.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
n.getController().Lock()
|
||||||
|
netWatch, ok := n.getController().nmap[n.ID()]
|
||||||
|
n.getController().Unlock()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("watch null for network %q", n.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
n.updateSvcRecord(ep, n.getController().getLocalEps(netWatch), false)
|
||||||
|
|
||||||
|
oldName := ep.name
|
||||||
|
ep.name = name
|
||||||
|
|
||||||
|
n.updateSvcRecord(ep, n.getController().getLocalEps(netWatch), true)
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
n.updateSvcRecord(ep, n.getController().getLocalEps(netWatch), false)
|
||||||
|
ep.name = oldName
|
||||||
|
n.updateSvcRecord(ep, n.getController().getLocalEps(netWatch), true)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Update the store with the updated name
|
||||||
|
if err = n.getController().updateToStore(ep); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// After the name change do a dummy endpoint count update to
|
||||||
|
// trigger the service record update in the peer nodes
|
||||||
|
|
||||||
|
// Ignore the error because updateStore fail for EpCnt is a
|
||||||
|
// benign error. Besides there is no meaningful recovery that
|
||||||
|
// we can do. When the cluster recovers subsequent EpCnt update
|
||||||
|
// will force the peers to get the correct EP name.
|
||||||
|
n.getEpCnt().updateStore()
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (ep *endpoint) hasInterface(iName string) bool {
|
func (ep *endpoint) hasInterface(iName string) bool {
|
||||||
ep.Lock()
|
ep.Lock()
|
||||||
defer ep.Unlock()
|
defer ep.Unlock()
|
||||||
|
|
|
@ -108,6 +108,21 @@ func (ec *endpointCnt) EndpointCnt() uint64 {
|
||||||
return ec.Count
|
return ec.Count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *endpointCnt) updateStore() error {
|
||||||
|
store := ec.n.getController().getStore(ec.DataScope())
|
||||||
|
if store == nil {
|
||||||
|
return fmt.Errorf("store not found for scope %s on endpoint count update", ec.DataScope())
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
if err := ec.n.getController().updateToStore(ec); err == nil || err != datastore.ErrKeyModified {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := store.GetObject(datastore.Key(ec.Key()...), ec); err != nil {
|
||||||
|
return fmt.Errorf("could not update the kvobject to latest on endpoint count update: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *endpointCnt) atomicIncDecEpCnt(inc bool) error {
|
func (ec *endpointCnt) atomicIncDecEpCnt(inc bool) error {
|
||||||
retry:
|
retry:
|
||||||
ec.Lock()
|
ec.Lock()
|
||||||
|
|
|
@ -34,6 +34,8 @@ type Sandbox interface {
|
||||||
Refresh(options ...SandboxOption) error
|
Refresh(options ...SandboxOption) error
|
||||||
// SetKey updates the Sandbox Key
|
// SetKey updates the Sandbox Key
|
||||||
SetKey(key string) error
|
SetKey(key string) error
|
||||||
|
// Rename changes the name of all attached Endpoints
|
||||||
|
Rename(name string) error
|
||||||
// Delete destroys this container after detaching it from all connected endpoints.
|
// Delete destroys this container after detaching it from all connected endpoints.
|
||||||
Delete() error
|
Delete() error
|
||||||
}
|
}
|
||||||
|
@ -201,6 +203,30 @@ func (sb *sandbox) Delete() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sb *sandbox) Rename(name string) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
for _, ep := range sb.getConnectedEndpoints() {
|
||||||
|
if ep.endpointInGWNetwork() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
oldName := ep.Name()
|
||||||
|
lEp := ep
|
||||||
|
if err = ep.rename(name); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
lEp.rename(oldName)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (sb *sandbox) Refresh(options ...SandboxOption) error {
|
func (sb *sandbox) Refresh(options ...SandboxOption) error {
|
||||||
// Store connected endpoints
|
// Store connected endpoints
|
||||||
epList := sb.getConnectedEndpoints()
|
epList := sb.getConnectedEndpoints()
|
||||||
|
|
33
vendor/src/github.com/docker/libnetwork/store.go
vendored
33
vendor/src/github.com/docker/libnetwork/store.go
vendored
|
@ -274,25 +274,30 @@ func (c *controller) networkWatchLoop(nw *netWatch, ep *endpoint, ecCh <-chan da
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := nw.remoteEps[lEp.ID()]; ok {
|
if ep, ok := nw.remoteEps[lEp.ID()]; ok {
|
||||||
delete(delEpMap, lEp.ID())
|
// On a container rename EP ID will remain
|
||||||
continue
|
// the same but the name will change. service
|
||||||
|
// records should reflect the change.
|
||||||
|
// Keep old EP entry in the delEpMap and add
|
||||||
|
// EP from the store (which has the new name)
|
||||||
|
// into the new list
|
||||||
|
if lEp.name == ep.name {
|
||||||
|
delete(delEpMap, lEp.ID())
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nw.remoteEps[lEp.ID()] = lEp
|
nw.remoteEps[lEp.ID()] = lEp
|
||||||
addEp = append(addEp, lEp)
|
addEp = append(addEp, lEp)
|
||||||
|
|
||||||
}
|
}
|
||||||
c.Unlock()
|
c.Unlock()
|
||||||
|
|
||||||
for _, lEp := range addEp {
|
|
||||||
ep.getNetwork().updateSvcRecord(lEp, c.getLocalEps(nw), true)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, lEp := range delEpMap {
|
for _, lEp := range delEpMap {
|
||||||
ep.getNetwork().updateSvcRecord(lEp, c.getLocalEps(nw), false)
|
ep.getNetwork().updateSvcRecord(lEp, c.getLocalEps(nw), false)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
for _, lEp := range addEp {
|
||||||
|
ep.getNetwork().updateSvcRecord(lEp, c.getLocalEps(nw), true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -378,13 +383,13 @@ func (c *controller) processEndpointDelete(nmap map[string]*netWatch, ep *endpoi
|
||||||
c.Unlock()
|
c.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) watchLoop(nmap map[string]*netWatch) {
|
func (c *controller) watchLoop() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case ep := <-c.watchCh:
|
case ep := <-c.watchCh:
|
||||||
c.processEndpointCreate(nmap, ep)
|
c.processEndpointCreate(c.nmap, ep)
|
||||||
case ep := <-c.unWatchCh:
|
case ep := <-c.unWatchCh:
|
||||||
c.processEndpointDelete(nmap, ep)
|
c.processEndpointDelete(c.nmap, ep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -392,7 +397,7 @@ func (c *controller) watchLoop(nmap map[string]*netWatch) {
|
||||||
func (c *controller) startWatch() {
|
func (c *controller) startWatch() {
|
||||||
c.watchCh = make(chan *endpoint)
|
c.watchCh = make(chan *endpoint)
|
||||||
c.unWatchCh = make(chan *endpoint)
|
c.unWatchCh = make(chan *endpoint)
|
||||||
nmap := make(map[string]*netWatch)
|
c.nmap = make(map[string]*netWatch)
|
||||||
|
|
||||||
go c.watchLoop(nmap)
|
go c.watchLoop()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue