github.com/moby/docker@v26.1.3+incompatible/daemon/rename.go (about) 1 package daemon // import "github.com/docker/docker/daemon" 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 8 "github.com/containerd/log" 9 "github.com/docker/docker/api/types/events" 10 dockercontainer "github.com/docker/docker/container" 11 "github.com/docker/docker/daemon/network" 12 "github.com/docker/docker/errdefs" 13 "github.com/docker/docker/libnetwork" 14 "github.com/pkg/errors" 15 ) 16 17 // ContainerRename changes the name of a container, using the oldName 18 // to find the container. An error is returned if newName is already 19 // reserved. 20 func (daemon *Daemon) ContainerRename(oldName, newName string) (retErr error) { 21 if oldName == "" || newName == "" { 22 return errdefs.InvalidParameter(errors.New("Neither old nor new names may be empty")) 23 } 24 25 container, err := daemon.GetContainer(oldName) 26 if err != nil { 27 return err 28 } 29 container.Lock() 30 defer container.Unlock() 31 32 // Canonicalize name for comparing. 33 if newName[0] != '/' { 34 newName = "/" + newName 35 } 36 if container.Name == newName { 37 return errdefs.InvalidParameter(errors.New("Renaming a container with the same name as its current name")) 38 } 39 40 links := map[string]*dockercontainer.Container{} 41 for k, v := range daemon.linkIndex.children(container) { 42 if !strings.HasPrefix(k, container.Name) { 43 return errdefs.InvalidParameter(errors.Errorf("Linked container %s does not match parent %s", k, container.Name)) 44 } 45 links[strings.TrimPrefix(k, container.Name)] = v 46 } 47 48 newName, err = daemon.reserveName(container.ID, newName) 49 if err != nil { 50 return errors.Wrap(err, "Error when allocating new name") 51 } 52 53 for k, v := range links { 54 daemon.containersReplica.ReserveName(newName+k, v.ID) 55 daemon.linkIndex.link(container, v, newName+k) 56 } 57 58 oldName = container.Name 59 container.Name = newName 60 61 defer func() { 62 if retErr != nil { 63 container.Name = oldName 64 daemon.reserveName(container.ID, oldName) 65 for k, v := range links { 66 daemon.containersReplica.ReserveName(oldName+k, v.ID) 67 daemon.linkIndex.link(container, v, oldName+k) 68 daemon.linkIndex.unlink(newName+k, v, container) 69 daemon.containersReplica.ReleaseName(newName + k) 70 } 71 daemon.releaseName(newName) 72 } else { 73 daemon.releaseName(oldName) 74 } 75 }() 76 77 for k, v := range links { 78 daemon.linkIndex.unlink(oldName+k, v, container) 79 daemon.containersReplica.ReleaseName(oldName + k) 80 } 81 if err := container.CheckpointTo(daemon.containersReplica); err != nil { 82 return err 83 } 84 85 if !container.Running { 86 daemon.LogContainerEventWithAttributes(container, events.ActionRename, map[string]string{ 87 "oldName": oldName, 88 }) 89 return nil 90 } 91 92 defer func() { 93 if retErr != nil { 94 container.Name = oldName 95 if err := container.CheckpointTo(daemon.containersReplica); err != nil { 96 log.G(context.TODO()).WithFields(log.Fields{ 97 "containerID": container.ID, 98 "error": err, 99 }).Error("failed to write container state to disk during rename") 100 } 101 } 102 }() 103 104 if sid := container.NetworkSettings.SandboxID; sid != "" && daemon.netController != nil { 105 sb, err := daemon.netController.SandboxByID(sid) 106 if err != nil { 107 return err 108 } 109 if err = sb.Rename(strings.TrimPrefix(container.Name, "/")); err != nil { 110 return err 111 } 112 defer func() { 113 if retErr != nil { 114 if err := sb.Rename(oldName); err != nil { 115 log.G(context.TODO()).WithFields(log.Fields{ 116 "sandboxID": sid, 117 "oldName": oldName, 118 "newName": newName, 119 "error": err, 120 }).Errorf("failed to revert sandbox rename") 121 } 122 } 123 }() 124 125 for nwName, epConfig := range container.NetworkSettings.Networks { 126 nw, err := daemon.FindNetwork(nwName) 127 if err != nil { 128 return err 129 } 130 131 ep := sb.GetEndpoint(epConfig.EndpointID) 132 if ep == nil { 133 return fmt.Errorf("no endpoint attached to network %s found", nw.Name()) 134 } 135 136 oldDNSNames := make([]string, len(epConfig.DNSNames)) 137 copy(oldDNSNames, epConfig.DNSNames) 138 139 epConfig.DNSNames = buildEndpointDNSNames(container, epConfig.Aliases) 140 if err := ep.UpdateDNSNames(epConfig.DNSNames); err != nil { 141 return err 142 } 143 144 defer func(ep *libnetwork.Endpoint, epConfig *network.EndpointSettings, oldDNSNames []string) { 145 if retErr == nil { 146 return 147 } 148 149 epConfig.DNSNames = oldDNSNames 150 if err := ep.UpdateDNSNames(epConfig.DNSNames); err != nil { 151 log.G(context.TODO()).WithFields(log.Fields{ 152 "sandboxID": sid, 153 "oldName": oldName, 154 "newName": newName, 155 "error": err, 156 }).Errorf("failed to revert DNSNames update") 157 } 158 }(ep, epConfig, oldDNSNames) 159 } 160 } 161 162 daemon.LogContainerEventWithAttributes(container, events.ActionRename, map[string]string{ 163 "oldName": oldName, 164 }) 165 return nil 166 }