github.com/akerouanton/docker@v1.11.0-rc3/daemon/start.go (about) 1 package daemon 2 3 import ( 4 "fmt" 5 "net/http" 6 "runtime" 7 "strings" 8 "syscall" 9 10 "github.com/Sirupsen/logrus" 11 "github.com/docker/docker/container" 12 "github.com/docker/docker/errors" 13 "github.com/docker/docker/libcontainerd" 14 "github.com/docker/docker/runconfig" 15 containertypes "github.com/docker/engine-api/types/container" 16 ) 17 18 // ContainerStart starts a container. 19 func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.HostConfig) error { 20 container, err := daemon.GetContainer(name) 21 if err != nil { 22 return err 23 } 24 25 if container.IsPaused() { 26 return fmt.Errorf("Cannot start a paused container, try unpause instead.") 27 } 28 29 if container.IsRunning() { 30 err := fmt.Errorf("Container already started") 31 return errors.NewErrorWithStatusCode(err, http.StatusNotModified) 32 } 33 34 // Windows does not have the backwards compatibility issue here. 35 if runtime.GOOS != "windows" { 36 // This is kept for backward compatibility - hostconfig should be passed when 37 // creating a container, not during start. 38 if hostConfig != nil { 39 logrus.Warn("DEPRECATED: Setting host configuration options when the container starts is deprecated and will be removed in Docker 1.12") 40 oldNetworkMode := container.HostConfig.NetworkMode 41 if err := daemon.setSecurityOptions(container, hostConfig); err != nil { 42 return err 43 } 44 if err := daemon.setHostConfig(container, hostConfig); err != nil { 45 return err 46 } 47 newNetworkMode := container.HostConfig.NetworkMode 48 if string(oldNetworkMode) != string(newNetworkMode) { 49 // if user has change the network mode on starting, clean up the 50 // old networks. It is a deprecated feature and will be removed in Docker 1.12 51 container.NetworkSettings.Networks = nil 52 if err := container.ToDisk(); err != nil { 53 return err 54 } 55 } 56 container.InitDNSHostConfig() 57 } 58 } else { 59 if hostConfig != nil { 60 return fmt.Errorf("Supplying a hostconfig on start is not supported. It should be supplied on create") 61 } 62 } 63 64 // check if hostConfig is in line with the current system settings. 65 // It may happen cgroups are umounted or the like. 66 if _, err = daemon.verifyContainerSettings(container.HostConfig, nil, false); err != nil { 67 return err 68 } 69 // Adapt for old containers in case we have updates in this function and 70 // old containers never have chance to call the new function in create stage. 71 if err := daemon.adaptContainerSettings(container.HostConfig, false); err != nil { 72 return err 73 } 74 75 return daemon.containerStart(container) 76 } 77 78 // Start starts a container 79 func (daemon *Daemon) Start(container *container.Container) error { 80 return daemon.containerStart(container) 81 } 82 83 // containerStart prepares the container to run by setting up everything the 84 // container needs, such as storage and networking, as well as links 85 // between containers. The container is left waiting for a signal to 86 // begin running. 87 func (daemon *Daemon) containerStart(container *container.Container) (err error) { 88 container.Lock() 89 defer container.Unlock() 90 91 if container.Running { 92 return nil 93 } 94 95 if container.RemovalInProgress || container.Dead { 96 return fmt.Errorf("Container is marked for removal and cannot be started.") 97 } 98 99 // if we encounter an error during start we need to ensure that any other 100 // setup has been cleaned up properly 101 defer func() { 102 if err != nil { 103 container.SetError(err) 104 // if no one else has set it, make sure we don't leave it at zero 105 if container.ExitCode == 0 { 106 container.ExitCode = 128 107 } 108 container.ToDisk() 109 daemon.Cleanup(container) 110 attributes := map[string]string{ 111 "exitCode": fmt.Sprintf("%d", container.ExitCode), 112 } 113 daemon.LogContainerEventWithAttributes(container, "die", attributes) 114 } 115 }() 116 117 if err := daemon.conditionalMountOnStart(container); err != nil { 118 return err 119 } 120 121 // Make sure NetworkMode has an acceptable value. We do this to ensure 122 // backwards API compatibility. 123 container.HostConfig = runconfig.SetDefaultNetModeIfBlank(container.HostConfig) 124 125 if err := daemon.initializeNetworking(container); err != nil { 126 return err 127 } 128 129 spec, err := daemon.createSpec(container) 130 if err != nil { 131 return err 132 } 133 134 defer daemon.LogContainerEvent(container, "start") // this is logged even on error 135 if err := daemon.containerd.Create(container.ID, *spec, libcontainerd.WithRestartManager(container.RestartManager(true))); err != nil { 136 // if we receive an internal error from the initial start of a container then lets 137 // return it instead of entering the restart loop 138 // set to 127 for container cmd not found/does not exist) 139 if strings.Contains(err.Error(), "executable file not found") || 140 strings.Contains(err.Error(), "no such file or directory") || 141 strings.Contains(err.Error(), "system cannot find the file specified") { 142 container.ExitCode = 127 143 err = fmt.Errorf("Container command '%s' not found or does not exist.", container.Path) 144 } 145 // set to 126 for container cmd can't be invoked errors 146 if strings.Contains(err.Error(), syscall.EACCES.Error()) { 147 container.ExitCode = 126 148 err = fmt.Errorf("Container command '%s' could not be invoked.", container.Path) 149 } 150 151 container.Reset(false) 152 return err 153 } 154 155 return nil 156 } 157 158 // Cleanup releases any network resources allocated to the container along with any rules 159 // around how containers are linked together. It also unmounts the container's root filesystem. 160 func (daemon *Daemon) Cleanup(container *container.Container) { 161 daemon.releaseNetwork(container) 162 163 container.UnmountIpcMounts(detachMounted) 164 165 if err := daemon.conditionalUnmountOnCleanup(container); err != nil { 166 // FIXME: remove once reference counting for graphdrivers has been refactored 167 // Ensure that all the mounts are gone 168 if mountid, err := daemon.layerStore.GetMountID(container.ID); err == nil { 169 daemon.cleanupMountsByID(mountid) 170 } 171 } 172 173 for _, eConfig := range container.ExecCommands.Commands() { 174 daemon.unregisterExecCommand(container, eConfig) 175 } 176 177 if container.BaseFS != "" { 178 if err := container.UnmountVolumes(false, daemon.LogVolumeEvent); err != nil { 179 logrus.Warnf("%s cleanup: Failed to umount volumes: %v", container.ID, err) 180 } 181 } 182 container.CancelAttachContext() 183 }