1128fc1add
Currently, names are maintained by a separate system called "registrar". This means there is no way to atomically snapshot the state of containers and the names associated with them. We can add this atomicity and simplify the code by storing name associations in the memdb. This removes the need for pkg/registrar, and makes snapshots a lot less expensive because they no longer need to copy all the names. This change also avoids some problematic behavior from pkg/registrar where it returns slices which may be modified later on. Note that while this change makes the *snapshotting* atomic, it doesn't yet do anything to make sure containers are named at the same time that they are added to the database. We can do that by adding a transactional interface, either as a followup, or as part of this PR. Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
123 lines
3.1 KiB
Go
123 lines
3.1 KiB
Go
package daemon
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
dockercontainer "github.com/docker/docker/container"
|
|
"github.com/docker/libnetwork"
|
|
)
|
|
|
|
// ContainerRename changes the name of a container, using the oldName
|
|
// to find the container. An error is returned if newName is already
|
|
// reserved.
|
|
func (daemon *Daemon) ContainerRename(oldName, newName string) error {
|
|
var (
|
|
sid string
|
|
sb libnetwork.Sandbox
|
|
)
|
|
|
|
if oldName == "" || newName == "" {
|
|
return errors.New("Neither old nor new names may be empty")
|
|
}
|
|
|
|
if newName[0] != '/' {
|
|
newName = "/" + newName
|
|
}
|
|
|
|
container, err := daemon.GetContainer(oldName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
container.Lock()
|
|
defer container.Unlock()
|
|
|
|
oldName = container.Name
|
|
oldIsAnonymousEndpoint := container.NetworkSettings.IsAnonymousEndpoint
|
|
|
|
if oldName == newName {
|
|
return errors.New("Renaming a container with the same name as its current name")
|
|
}
|
|
|
|
links := map[string]*dockercontainer.Container{}
|
|
for k, v := range daemon.linkIndex.children(container) {
|
|
if !strings.HasPrefix(k, oldName) {
|
|
return fmt.Errorf("Linked container %s does not match parent %s", k, oldName)
|
|
}
|
|
links[strings.TrimPrefix(k, oldName)] = v
|
|
}
|
|
|
|
if newName, err = daemon.reserveName(container.ID, newName); err != nil {
|
|
return fmt.Errorf("Error when allocating new name: %v", err)
|
|
}
|
|
|
|
for k, v := range links {
|
|
daemon.containersReplica.ReserveName(newName+k, v.ID)
|
|
daemon.linkIndex.link(container, v, newName+k)
|
|
}
|
|
|
|
container.Name = newName
|
|
container.NetworkSettings.IsAnonymousEndpoint = false
|
|
|
|
defer func() {
|
|
if err != nil {
|
|
container.Name = oldName
|
|
container.NetworkSettings.IsAnonymousEndpoint = oldIsAnonymousEndpoint
|
|
daemon.reserveName(container.ID, oldName)
|
|
for k, v := range links {
|
|
daemon.containersReplica.ReserveName(oldName+k, v.ID)
|
|
daemon.linkIndex.link(container, v, oldName+k)
|
|
daemon.linkIndex.unlink(newName+k, v, container)
|
|
daemon.containersReplica.ReleaseName(newName + k)
|
|
}
|
|
daemon.releaseName(newName)
|
|
}
|
|
}()
|
|
|
|
for k, v := range links {
|
|
daemon.linkIndex.unlink(oldName+k, v, container)
|
|
daemon.containersReplica.ReleaseName(oldName + k)
|
|
}
|
|
daemon.releaseName(oldName)
|
|
if err = container.CheckpointTo(daemon.containersReplica); err != nil {
|
|
return err
|
|
}
|
|
|
|
attributes := map[string]string{
|
|
"oldName": oldName,
|
|
}
|
|
|
|
if !container.Running {
|
|
daemon.LogContainerEventWithAttributes(container, "rename", attributes)
|
|
return nil
|
|
}
|
|
|
|
defer func() {
|
|
if err != nil {
|
|
container.Name = oldName
|
|
container.NetworkSettings.IsAnonymousEndpoint = oldIsAnonymousEndpoint
|
|
if e := container.CheckpointTo(daemon.containersReplica); e != nil {
|
|
logrus.Errorf("%s: Failed in writing to Disk on rename failure: %v", container.ID, e)
|
|
}
|
|
}
|
|
}()
|
|
|
|
sid = container.NetworkSettings.SandboxID
|
|
if sid != "" && daemon.netController != nil {
|
|
sb, err = daemon.netController.SandboxByID(sid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = sb.Rename(strings.TrimPrefix(container.Name, "/"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
daemon.LogContainerEventWithAttributes(container, "rename", attributes)
|
|
return nil
|
|
}
|