github.com/vincentwoo/docker@v0.7.3-0.20160116130405-82401a4b13c0/daemon/start.go (about) 1 package daemon 2 3 import ( 4 "runtime" 5 6 "github.com/Sirupsen/logrus" 7 "github.com/docker/docker/container" 8 derr "github.com/docker/docker/errors" 9 "github.com/docker/docker/runconfig" 10 containertypes "github.com/docker/engine-api/types/container" 11 ) 12 13 // ContainerStart starts a container. 14 func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.HostConfig) error { 15 container, err := daemon.GetContainer(name) 16 if err != nil { 17 return err 18 } 19 20 if container.IsPaused() { 21 return derr.ErrorCodeStartPaused 22 } 23 24 if container.IsRunning() { 25 return derr.ErrorCodeAlreadyStarted 26 } 27 28 // Windows does not have the backwards compatibility issue here. 29 if runtime.GOOS != "windows" { 30 // This is kept for backward compatibility - hostconfig should be passed when 31 // creating a container, not during start. 32 if hostConfig != nil { 33 logrus.Warn("DEPRECATED: Setting host configuration options when the container starts is deprecated and will be removed in Docker 1.12") 34 oldNetworkMode := container.HostConfig.NetworkMode 35 if err := daemon.setSecurityOptions(container, hostConfig); err != nil { 36 return err 37 } 38 if err := daemon.setHostConfig(container, hostConfig); err != nil { 39 return err 40 } 41 newNetworkMode := container.HostConfig.NetworkMode 42 if string(oldNetworkMode) != string(newNetworkMode) { 43 // if user has change the network mode on starting, clean up the 44 // old networks. It is a deprecated feature and will be removed in Docker 1.12 45 container.NetworkSettings.Networks = nil 46 if err := container.ToDisk(); err != nil { 47 return err 48 } 49 } 50 container.InitDNSHostConfig() 51 } 52 } else { 53 if hostConfig != nil { 54 return derr.ErrorCodeHostConfigStart 55 } 56 } 57 58 // check if hostConfig is in line with the current system settings. 59 // It may happen cgroups are umounted or the like. 60 if _, err = daemon.verifyContainerSettings(container.HostConfig, nil); err != nil { 61 return err 62 } 63 // Adapt for old containers in case we have updates in this function and 64 // old containers never have chance to call the new function in create stage. 65 if err := daemon.adaptContainerSettings(container.HostConfig, false); err != nil { 66 return err 67 } 68 69 return daemon.containerStart(container) 70 } 71 72 // Start starts a container 73 func (daemon *Daemon) Start(container *container.Container) error { 74 return daemon.containerStart(container) 75 } 76 77 // containerStart prepares the container to run by setting up everything the 78 // container needs, such as storage and networking, as well as links 79 // between containers. The container is left waiting for a signal to 80 // begin running. 81 func (daemon *Daemon) containerStart(container *container.Container) (err error) { 82 container.Lock() 83 defer container.Unlock() 84 85 if container.Running { 86 return nil 87 } 88 89 if container.RemovalInProgress || container.Dead { 90 return derr.ErrorCodeContainerBeingRemoved 91 } 92 93 // if we encounter an error during start we need to ensure that any other 94 // setup has been cleaned up properly 95 defer func() { 96 if err != nil { 97 container.SetError(err) 98 // if no one else has set it, make sure we don't leave it at zero 99 if container.ExitCode == 0 { 100 container.ExitCode = 128 101 } 102 container.ToDisk() 103 daemon.Cleanup(container) 104 daemon.LogContainerEvent(container, "die") 105 } 106 }() 107 108 if err := daemon.conditionalMountOnStart(container); err != nil { 109 return err 110 } 111 112 // Make sure NetworkMode has an acceptable value. We do this to ensure 113 // backwards API compatibility. 114 container.HostConfig = runconfig.SetDefaultNetModeIfBlank(container.HostConfig) 115 116 if err := daemon.initializeNetworking(container); err != nil { 117 return err 118 } 119 linkedEnv, err := daemon.setupLinkedContainers(container) 120 if err != nil { 121 return err 122 } 123 if err := container.SetupWorkingDirectory(); err != nil { 124 return err 125 } 126 env := container.CreateDaemonEnvironment(linkedEnv) 127 if err := daemon.populateCommand(container, env); err != nil { 128 return err 129 } 130 131 if !container.HostConfig.IpcMode.IsContainer() && !container.HostConfig.IpcMode.IsHost() { 132 if err := daemon.setupIpcDirs(container); err != nil { 133 return err 134 } 135 } 136 137 mounts, err := daemon.setupMounts(container) 138 if err != nil { 139 return err 140 } 141 mounts = append(mounts, container.IpcMounts()...) 142 mounts = append(mounts, container.TmpfsMounts()...) 143 144 container.Command.Mounts = mounts 145 if err := daemon.waitForStart(container); err != nil { 146 return err 147 } 148 container.HasBeenStartedBefore = true 149 return nil 150 } 151 152 func (daemon *Daemon) waitForStart(container *container.Container) error { 153 return container.StartMonitor(daemon, container.HostConfig.RestartPolicy) 154 } 155 156 // Cleanup releases any network resources allocated to the container along with any rules 157 // around how containers are linked together. It also unmounts the container's root filesystem. 158 func (daemon *Daemon) Cleanup(container *container.Container) { 159 daemon.releaseNetwork(container) 160 161 container.UnmountIpcMounts(detachMounted) 162 163 daemon.conditionalUnmountOnCleanup(container) 164 165 for _, eConfig := range container.ExecCommands.Commands() { 166 daemon.unregisterExecCommand(container, eConfig) 167 } 168 169 if err := container.UnmountVolumes(false, daemon.LogVolumeEvent); err != nil { 170 logrus.Warnf("%s cleanup: Failed to umount volumes: %v", container.ID, err) 171 } 172 }