| package daemon // import "github.com/docker/docker/daemon" |
| |
| import ( |
| "strings" |
| |
| dockercontainer "github.com/docker/docker/container" |
| "github.com/docker/docker/errdefs" |
| "github.com/docker/libnetwork" |
| "github.com/pkg/errors" |
| "github.com/sirupsen/logrus" |
| ) |
| |
| // 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 errdefs.InvalidParameter(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 errdefs.InvalidParameter(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 errdefs.InvalidParameter(errors.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 errors.Wrap(err, "Error when allocating new name") |
| } |
| |
| 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 |
| } |