container.go 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106
  1. package container
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "net"
  7. "os"
  8. "path/filepath"
  9. "strconv"
  10. "strings"
  11. "sync"
  12. "syscall"
  13. "time"
  14. "golang.org/x/net/context"
  15. "github.com/Sirupsen/logrus"
  16. containertypes "github.com/docker/docker/api/types/container"
  17. mounttypes "github.com/docker/docker/api/types/mount"
  18. networktypes "github.com/docker/docker/api/types/network"
  19. "github.com/docker/docker/container/stream"
  20. "github.com/docker/docker/daemon/exec"
  21. "github.com/docker/docker/daemon/logger"
  22. "github.com/docker/docker/daemon/logger/jsonfilelog"
  23. "github.com/docker/docker/daemon/network"
  24. "github.com/docker/docker/image"
  25. "github.com/docker/docker/layer"
  26. "github.com/docker/docker/libcontainerd"
  27. "github.com/docker/docker/pkg/idtools"
  28. "github.com/docker/docker/pkg/ioutils"
  29. "github.com/docker/docker/pkg/promise"
  30. "github.com/docker/docker/pkg/signal"
  31. "github.com/docker/docker/pkg/symlink"
  32. "github.com/docker/docker/restartmanager"
  33. "github.com/docker/docker/runconfig"
  34. runconfigopts "github.com/docker/docker/runconfig/opts"
  35. "github.com/docker/docker/volume"
  36. "github.com/docker/go-connections/nat"
  37. "github.com/docker/libnetwork"
  38. "github.com/docker/libnetwork/netlabel"
  39. "github.com/docker/libnetwork/options"
  40. "github.com/docker/libnetwork/types"
  41. "github.com/opencontainers/runc/libcontainer/label"
  42. )
  43. const configFileName = "config.v2.json"
  44. const (
  45. // DefaultStopTimeout is the timeout (in seconds) for the syscall signal used to stop a container.
  46. DefaultStopTimeout = 10
  47. )
  48. var (
  49. errInvalidEndpoint = fmt.Errorf("invalid endpoint while building port map info")
  50. errInvalidNetwork = fmt.Errorf("invalid network settings while building port map info")
  51. )
  52. // DetachError is special error which returned in case of container detach.
  53. type DetachError struct{}
  54. func (DetachError) Error() string {
  55. return "detached from container"
  56. }
  57. // CommonContainer holds the fields for a container which are
  58. // applicable across all platforms supported by the daemon.
  59. type CommonContainer struct {
  60. StreamConfig *stream.Config
  61. // embed for Container to support states directly.
  62. *State `json:"State"` // Needed for remote api version <= 1.11
  63. Root string `json:"-"` // Path to the "home" of the container, including metadata.
  64. BaseFS string `json:"-"` // Path to the graphdriver mountpoint
  65. RWLayer layer.RWLayer `json:"-"`
  66. ID string
  67. Created time.Time
  68. Managed bool
  69. Path string
  70. Args []string
  71. Config *containertypes.Config
  72. ImageID image.ID `json:"Image"`
  73. NetworkSettings *network.Settings
  74. LogPath string
  75. Name string
  76. Driver string
  77. // MountLabel contains the options for the 'mount' command
  78. MountLabel string
  79. ProcessLabel string
  80. RestartCount int
  81. HasBeenStartedBefore bool
  82. HasBeenManuallyStopped bool // used for unless-stopped restart policy
  83. MountPoints map[string]*volume.MountPoint
  84. HostConfig *containertypes.HostConfig `json:"-"` // do not serialize the host config in the json, otherwise we'll make the container unportable
  85. ExecCommands *exec.Store `json:"-"`
  86. Secrets []*containertypes.ContainerSecret `json:"-"` // do not serialize
  87. // logDriver for closing
  88. LogDriver logger.Logger `json:"-"`
  89. LogCopier *logger.Copier `json:"-"`
  90. restartManager restartmanager.RestartManager
  91. attachContext *attachContext
  92. }
  93. // NewBaseContainer creates a new container with its
  94. // basic configuration.
  95. func NewBaseContainer(id, root string) *Container {
  96. return &Container{
  97. CommonContainer: CommonContainer{
  98. ID: id,
  99. State: NewState(),
  100. ExecCommands: exec.NewStore(),
  101. Root: root,
  102. MountPoints: make(map[string]*volume.MountPoint),
  103. StreamConfig: stream.NewConfig(),
  104. attachContext: &attachContext{},
  105. },
  106. }
  107. }
  108. // FromDisk loads the container configuration stored in the host.
  109. func (container *Container) FromDisk() error {
  110. pth, err := container.ConfigPath()
  111. if err != nil {
  112. return err
  113. }
  114. jsonSource, err := os.Open(pth)
  115. if err != nil {
  116. return err
  117. }
  118. defer jsonSource.Close()
  119. dec := json.NewDecoder(jsonSource)
  120. // Load container settings
  121. if err := dec.Decode(container); err != nil {
  122. return err
  123. }
  124. if err := label.ReserveLabel(container.ProcessLabel); err != nil {
  125. return err
  126. }
  127. return container.readHostConfig()
  128. }
  129. // ToDisk saves the container configuration on disk.
  130. func (container *Container) ToDisk() error {
  131. pth, err := container.ConfigPath()
  132. if err != nil {
  133. return err
  134. }
  135. jsonSource, err := ioutils.NewAtomicFileWriter(pth, 0644)
  136. if err != nil {
  137. return err
  138. }
  139. defer jsonSource.Close()
  140. enc := json.NewEncoder(jsonSource)
  141. // Save container settings
  142. if err := enc.Encode(container); err != nil {
  143. return err
  144. }
  145. return container.WriteHostConfig()
  146. }
  147. // ToDiskLocking saves the container configuration on disk in a thread safe way.
  148. func (container *Container) ToDiskLocking() error {
  149. container.Lock()
  150. err := container.ToDisk()
  151. container.Unlock()
  152. return err
  153. }
  154. // readHostConfig reads the host configuration from disk for the container.
  155. func (container *Container) readHostConfig() error {
  156. container.HostConfig = &containertypes.HostConfig{}
  157. // If the hostconfig file does not exist, do not read it.
  158. // (We still have to initialize container.HostConfig,
  159. // but that's OK, since we just did that above.)
  160. pth, err := container.HostConfigPath()
  161. if err != nil {
  162. return err
  163. }
  164. f, err := os.Open(pth)
  165. if err != nil {
  166. if os.IsNotExist(err) {
  167. return nil
  168. }
  169. return err
  170. }
  171. defer f.Close()
  172. if err := json.NewDecoder(f).Decode(&container.HostConfig); err != nil {
  173. return err
  174. }
  175. container.InitDNSHostConfig()
  176. return nil
  177. }
  178. // WriteHostConfig saves the host configuration on disk for the container.
  179. func (container *Container) WriteHostConfig() error {
  180. pth, err := container.HostConfigPath()
  181. if err != nil {
  182. return err
  183. }
  184. f, err := ioutils.NewAtomicFileWriter(pth, 0644)
  185. if err != nil {
  186. return err
  187. }
  188. defer f.Close()
  189. return json.NewEncoder(f).Encode(&container.HostConfig)
  190. }
  191. // SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir
  192. func (container *Container) SetupWorkingDirectory(rootUID, rootGID int) error {
  193. if container.Config.WorkingDir == "" {
  194. return nil
  195. }
  196. container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir)
  197. // If can't mount container FS at this point (eg Hyper-V Containers on
  198. // Windows) bail out now with no action.
  199. if !container.canMountFS() {
  200. return nil
  201. }
  202. pth, err := container.GetResourcePath(container.Config.WorkingDir)
  203. if err != nil {
  204. return err
  205. }
  206. if err := idtools.MkdirAllNewAs(pth, 0755, rootUID, rootGID); err != nil {
  207. pthInfo, err2 := os.Stat(pth)
  208. if err2 == nil && pthInfo != nil && !pthInfo.IsDir() {
  209. return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)
  210. }
  211. return err
  212. }
  213. return nil
  214. }
  215. // GetResourcePath evaluates `path` in the scope of the container's BaseFS, with proper path
  216. // sanitisation. Symlinks are all scoped to the BaseFS of the container, as
  217. // though the container's BaseFS was `/`.
  218. //
  219. // The BaseFS of a container is the host-facing path which is bind-mounted as
  220. // `/` inside the container. This method is essentially used to access a
  221. // particular path inside the container as though you were a process in that
  222. // container.
  223. //
  224. // NOTE: The returned path is *only* safely scoped inside the container's BaseFS
  225. // if no component of the returned path changes (such as a component
  226. // symlinking to a different path) between using this method and using the
  227. // path. See symlink.FollowSymlinkInScope for more details.
  228. func (container *Container) GetResourcePath(path string) (string, error) {
  229. // IMPORTANT - These are paths on the OS where the daemon is running, hence
  230. // any filepath operations must be done in an OS agnostic way.
  231. cleanPath := cleanResourcePath(path)
  232. r, e := symlink.FollowSymlinkInScope(filepath.Join(container.BaseFS, cleanPath), container.BaseFS)
  233. // Log this here on the daemon side as there's otherwise no indication apart
  234. // from the error being propagated all the way back to the client. This makes
  235. // debugging significantly easier and clearly indicates the error comes from the daemon.
  236. if e != nil {
  237. logrus.Errorf("Failed to FollowSymlinkInScope BaseFS %s cleanPath %s path %s %s\n", container.BaseFS, cleanPath, path, e)
  238. }
  239. return r, e
  240. }
  241. // GetRootResourcePath evaluates `path` in the scope of the container's root, with proper path
  242. // sanitisation. Symlinks are all scoped to the root of the container, as
  243. // though the container's root was `/`.
  244. //
  245. // The root of a container is the host-facing configuration metadata directory.
  246. // Only use this method to safely access the container's `container.json` or
  247. // other metadata files. If in doubt, use container.GetResourcePath.
  248. //
  249. // NOTE: The returned path is *only* safely scoped inside the container's root
  250. // if no component of the returned path changes (such as a component
  251. // symlinking to a different path) between using this method and using the
  252. // path. See symlink.FollowSymlinkInScope for more details.
  253. func (container *Container) GetRootResourcePath(path string) (string, error) {
  254. // IMPORTANT - These are paths on the OS where the daemon is running, hence
  255. // any filepath operations must be done in an OS agnostic way.
  256. cleanPath := filepath.Join(string(os.PathSeparator), path)
  257. return symlink.FollowSymlinkInScope(filepath.Join(container.Root, cleanPath), container.Root)
  258. }
  259. // ExitOnNext signals to the monitor that it should not restart the container
  260. // after we send the kill signal.
  261. func (container *Container) ExitOnNext() {
  262. container.RestartManager().Cancel()
  263. }
  264. // HostConfigPath returns the path to the container's JSON hostconfig
  265. func (container *Container) HostConfigPath() (string, error) {
  266. return container.GetRootResourcePath("hostconfig.json")
  267. }
  268. // ConfigPath returns the path to the container's JSON config
  269. func (container *Container) ConfigPath() (string, error) {
  270. return container.GetRootResourcePath(configFileName)
  271. }
  272. // CheckpointDir returns the directory checkpoints are stored in
  273. func (container *Container) CheckpointDir() string {
  274. return filepath.Join(container.Root, "checkpoints")
  275. }
  276. // StartLogger starts a new logger driver for the container.
  277. func (container *Container) StartLogger(cfg containertypes.LogConfig) (logger.Logger, error) {
  278. c, err := logger.GetLogDriver(cfg.Type)
  279. if err != nil {
  280. return nil, fmt.Errorf("Failed to get logging factory: %v", err)
  281. }
  282. ctx := logger.Context{
  283. Config: cfg.Config,
  284. ContainerID: container.ID,
  285. ContainerName: container.Name,
  286. ContainerEntrypoint: container.Path,
  287. ContainerArgs: container.Args,
  288. ContainerImageID: container.ImageID.String(),
  289. ContainerImageName: container.Config.Image,
  290. ContainerCreated: container.Created,
  291. ContainerEnv: container.Config.Env,
  292. ContainerLabels: container.Config.Labels,
  293. DaemonName: "docker",
  294. }
  295. // Set logging file for "json-logger"
  296. if cfg.Type == jsonfilelog.Name {
  297. ctx.LogPath, err = container.GetRootResourcePath(fmt.Sprintf("%s-json.log", container.ID))
  298. if err != nil {
  299. return nil, err
  300. }
  301. }
  302. return c(ctx)
  303. }
  304. // GetProcessLabel returns the process label for the container.
  305. func (container *Container) GetProcessLabel() string {
  306. // even if we have a process label return "" if we are running
  307. // in privileged mode
  308. if container.HostConfig.Privileged {
  309. return ""
  310. }
  311. return container.ProcessLabel
  312. }
  313. // GetMountLabel returns the mounting label for the container.
  314. // This label is empty if the container is privileged.
  315. func (container *Container) GetMountLabel() string {
  316. return container.MountLabel
  317. }
  318. // GetExecIDs returns the list of exec commands running on the container.
  319. func (container *Container) GetExecIDs() []string {
  320. return container.ExecCommands.List()
  321. }
  322. // Attach connects to the container's TTY, delegating to standard
  323. // streams or websockets depending on the configuration.
  324. func (container *Container) Attach(stdin io.ReadCloser, stdout io.Writer, stderr io.Writer, keys []byte) chan error {
  325. ctx := container.InitAttachContext()
  326. return AttachStreams(ctx, container.StreamConfig, container.Config.OpenStdin, container.Config.StdinOnce, container.Config.Tty, stdin, stdout, stderr, keys)
  327. }
  328. // AttachStreams connects streams to a TTY.
  329. // Used by exec too. Should this move somewhere else?
  330. func AttachStreams(ctx context.Context, streamConfig *stream.Config, openStdin, stdinOnce, tty bool, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer, keys []byte) chan error {
  331. var (
  332. cStdout, cStderr io.ReadCloser
  333. cStdin io.WriteCloser
  334. wg sync.WaitGroup
  335. errors = make(chan error, 3)
  336. )
  337. if stdin != nil && openStdin {
  338. cStdin = streamConfig.StdinPipe()
  339. wg.Add(1)
  340. }
  341. if stdout != nil {
  342. cStdout = streamConfig.StdoutPipe()
  343. wg.Add(1)
  344. }
  345. if stderr != nil {
  346. cStderr = streamConfig.StderrPipe()
  347. wg.Add(1)
  348. }
  349. // Connect stdin of container to the http conn.
  350. go func() {
  351. if stdin == nil || !openStdin {
  352. return
  353. }
  354. logrus.Debug("attach: stdin: begin")
  355. var err error
  356. if tty {
  357. _, err = copyEscapable(cStdin, stdin, keys)
  358. } else {
  359. _, err = io.Copy(cStdin, stdin)
  360. }
  361. if err == io.ErrClosedPipe {
  362. err = nil
  363. }
  364. if err != nil {
  365. logrus.Errorf("attach: stdin: %s", err)
  366. errors <- err
  367. }
  368. if stdinOnce && !tty {
  369. cStdin.Close()
  370. } else {
  371. // No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
  372. if cStdout != nil {
  373. cStdout.Close()
  374. }
  375. if cStderr != nil {
  376. cStderr.Close()
  377. }
  378. }
  379. logrus.Debug("attach: stdin: end")
  380. wg.Done()
  381. }()
  382. attachStream := func(name string, stream io.Writer, streamPipe io.ReadCloser) {
  383. if stream == nil {
  384. return
  385. }
  386. logrus.Debugf("attach: %s: begin", name)
  387. _, err := io.Copy(stream, streamPipe)
  388. if err == io.ErrClosedPipe {
  389. err = nil
  390. }
  391. if err != nil {
  392. logrus.Errorf("attach: %s: %v", name, err)
  393. errors <- err
  394. }
  395. // Make sure stdin gets closed
  396. if stdin != nil {
  397. stdin.Close()
  398. }
  399. streamPipe.Close()
  400. logrus.Debugf("attach: %s: end", name)
  401. wg.Done()
  402. }
  403. go attachStream("stdout", stdout, cStdout)
  404. go attachStream("stderr", stderr, cStderr)
  405. return promise.Go(func() error {
  406. done := make(chan struct{})
  407. go func() {
  408. wg.Wait()
  409. close(done)
  410. }()
  411. select {
  412. case <-done:
  413. case <-ctx.Done():
  414. // close all pipes
  415. if cStdin != nil {
  416. cStdin.Close()
  417. }
  418. if cStdout != nil {
  419. cStdout.Close()
  420. }
  421. if cStderr != nil {
  422. cStderr.Close()
  423. }
  424. <-done
  425. }
  426. close(errors)
  427. for err := range errors {
  428. if err != nil {
  429. return err
  430. }
  431. }
  432. return nil
  433. })
  434. }
  435. // Code c/c from io.Copy() modified to handle escape sequence
  436. func copyEscapable(dst io.Writer, src io.ReadCloser, keys []byte) (written int64, err error) {
  437. if len(keys) == 0 {
  438. // Default keys : ctrl-p ctrl-q
  439. keys = []byte{16, 17}
  440. }
  441. buf := make([]byte, 32*1024)
  442. for {
  443. nr, er := src.Read(buf)
  444. if nr > 0 {
  445. // ---- Docker addition
  446. preservBuf := []byte{}
  447. for i, key := range keys {
  448. preservBuf = append(preservBuf, buf[0:nr]...)
  449. if nr != 1 || buf[0] != key {
  450. break
  451. }
  452. if i == len(keys)-1 {
  453. src.Close()
  454. return 0, DetachError{}
  455. }
  456. nr, er = src.Read(buf)
  457. }
  458. var nw int
  459. var ew error
  460. if len(preservBuf) > 0 {
  461. nw, ew = dst.Write(preservBuf)
  462. nr = len(preservBuf)
  463. } else {
  464. // ---- End of docker
  465. nw, ew = dst.Write(buf[0:nr])
  466. }
  467. if nw > 0 {
  468. written += int64(nw)
  469. }
  470. if ew != nil {
  471. err = ew
  472. break
  473. }
  474. if nr != nw {
  475. err = io.ErrShortWrite
  476. break
  477. }
  478. }
  479. if er == io.EOF {
  480. break
  481. }
  482. if er != nil {
  483. err = er
  484. break
  485. }
  486. }
  487. return written, err
  488. }
  489. // ShouldRestart decides whether the daemon should restart the container or not.
  490. // This is based on the container's restart policy.
  491. func (container *Container) ShouldRestart() bool {
  492. shouldRestart, _, _ := container.RestartManager().ShouldRestart(uint32(container.ExitCode()), container.HasBeenManuallyStopped, container.FinishedAt.Sub(container.StartedAt))
  493. return shouldRestart
  494. }
  495. // AddMountPointWithVolume adds a new mount point configured with a volume to the container.
  496. func (container *Container) AddMountPointWithVolume(destination string, vol volume.Volume, rw bool) {
  497. container.MountPoints[destination] = &volume.MountPoint{
  498. Type: mounttypes.TypeVolume,
  499. Name: vol.Name(),
  500. Driver: vol.DriverName(),
  501. Destination: destination,
  502. RW: rw,
  503. Volume: vol,
  504. CopyData: volume.DefaultCopyMode,
  505. }
  506. }
  507. // UnmountVolumes unmounts all volumes
  508. func (container *Container) UnmountVolumes(volumeEventLog func(name, action string, attributes map[string]string)) error {
  509. var errors []string
  510. for _, volumeMount := range container.MountPoints {
  511. // Check if the mounpoint has an ID, this is currently the best way to tell if it's actually mounted
  512. // TODO(cpuguyh83): there should be a better way to handle this
  513. if volumeMount.Volume != nil && volumeMount.ID != "" {
  514. if err := volumeMount.Volume.Unmount(volumeMount.ID); err != nil {
  515. errors = append(errors, err.Error())
  516. continue
  517. }
  518. volumeMount.ID = ""
  519. attributes := map[string]string{
  520. "driver": volumeMount.Volume.DriverName(),
  521. "container": container.ID,
  522. }
  523. volumeEventLog(volumeMount.Volume.Name(), "unmount", attributes)
  524. }
  525. }
  526. if len(errors) > 0 {
  527. return fmt.Errorf("error while unmounting volumes for container %s: %s", container.ID, strings.Join(errors, "; "))
  528. }
  529. return nil
  530. }
  531. // IsDestinationMounted checks whether a path is mounted on the container or not.
  532. func (container *Container) IsDestinationMounted(destination string) bool {
  533. return container.MountPoints[destination] != nil
  534. }
  535. // StopSignal returns the signal used to stop the container.
  536. func (container *Container) StopSignal() int {
  537. var stopSignal syscall.Signal
  538. if container.Config.StopSignal != "" {
  539. stopSignal, _ = signal.ParseSignal(container.Config.StopSignal)
  540. }
  541. if int(stopSignal) == 0 {
  542. stopSignal, _ = signal.ParseSignal(signal.DefaultStopSignal)
  543. }
  544. return int(stopSignal)
  545. }
  546. // StopTimeout returns the timeout (in seconds) used to stop the container.
  547. func (container *Container) StopTimeout() int {
  548. if container.Config.StopTimeout != nil {
  549. return *container.Config.StopTimeout
  550. }
  551. return DefaultStopTimeout
  552. }
  553. // InitDNSHostConfig ensures that the dns fields are never nil.
  554. // New containers don't ever have those fields nil,
  555. // but pre created containers can still have those nil values.
  556. // The non-recommended host configuration in the start api can
  557. // make these fields nil again, this corrects that issue until
  558. // we remove that behavior for good.
  559. // See https://github.com/docker/docker/pull/17779
  560. // for a more detailed explanation on why we don't want that.
  561. func (container *Container) InitDNSHostConfig() {
  562. container.Lock()
  563. defer container.Unlock()
  564. if container.HostConfig.DNS == nil {
  565. container.HostConfig.DNS = make([]string, 0)
  566. }
  567. if container.HostConfig.DNSSearch == nil {
  568. container.HostConfig.DNSSearch = make([]string, 0)
  569. }
  570. if container.HostConfig.DNSOptions == nil {
  571. container.HostConfig.DNSOptions = make([]string, 0)
  572. }
  573. }
  574. // GetEndpointInNetwork returns the container's endpoint to the provided network.
  575. func (container *Container) GetEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) {
  576. endpointName := strings.TrimPrefix(container.Name, "/")
  577. return n.EndpointByName(endpointName)
  578. }
  579. func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error {
  580. if ep == nil {
  581. return errInvalidEndpoint
  582. }
  583. networkSettings := container.NetworkSettings
  584. if networkSettings == nil {
  585. return errInvalidNetwork
  586. }
  587. if len(networkSettings.Ports) == 0 {
  588. pm, err := getEndpointPortMapInfo(ep)
  589. if err != nil {
  590. return err
  591. }
  592. networkSettings.Ports = pm
  593. }
  594. return nil
  595. }
  596. func getEndpointPortMapInfo(ep libnetwork.Endpoint) (nat.PortMap, error) {
  597. pm := nat.PortMap{}
  598. driverInfo, err := ep.DriverInfo()
  599. if err != nil {
  600. return pm, err
  601. }
  602. if driverInfo == nil {
  603. // It is not an error for epInfo to be nil
  604. return pm, nil
  605. }
  606. if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
  607. if exposedPorts, ok := expData.([]types.TransportPort); ok {
  608. for _, tp := range exposedPorts {
  609. natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
  610. if err != nil {
  611. return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err)
  612. }
  613. pm[natPort] = nil
  614. }
  615. }
  616. }
  617. mapData, ok := driverInfo[netlabel.PortMap]
  618. if !ok {
  619. return pm, nil
  620. }
  621. if portMapping, ok := mapData.([]types.PortBinding); ok {
  622. for _, pp := range portMapping {
  623. natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
  624. if err != nil {
  625. return pm, err
  626. }
  627. natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
  628. pm[natPort] = append(pm[natPort], natBndg)
  629. }
  630. }
  631. return pm, nil
  632. }
  633. // GetSandboxPortMapInfo retrieves the current port-mapping programmed for the given sandbox
  634. func GetSandboxPortMapInfo(sb libnetwork.Sandbox) nat.PortMap {
  635. pm := nat.PortMap{}
  636. if sb == nil {
  637. return pm
  638. }
  639. for _, ep := range sb.Endpoints() {
  640. pm, _ = getEndpointPortMapInfo(ep)
  641. if len(pm) > 0 {
  642. break
  643. }
  644. }
  645. return pm
  646. }
  647. // BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
  648. func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
  649. if ep == nil {
  650. return errInvalidEndpoint
  651. }
  652. networkSettings := container.NetworkSettings
  653. if networkSettings == nil {
  654. return errInvalidNetwork
  655. }
  656. epInfo := ep.Info()
  657. if epInfo == nil {
  658. // It is not an error to get an empty endpoint info
  659. return nil
  660. }
  661. if _, ok := networkSettings.Networks[n.Name()]; !ok {
  662. networkSettings.Networks[n.Name()] = &network.EndpointSettings{
  663. EndpointSettings: &networktypes.EndpointSettings{},
  664. }
  665. }
  666. networkSettings.Networks[n.Name()].NetworkID = n.ID()
  667. networkSettings.Networks[n.Name()].EndpointID = ep.ID()
  668. iface := epInfo.Iface()
  669. if iface == nil {
  670. return nil
  671. }
  672. if iface.MacAddress() != nil {
  673. networkSettings.Networks[n.Name()].MacAddress = iface.MacAddress().String()
  674. }
  675. if iface.Address() != nil {
  676. ones, _ := iface.Address().Mask.Size()
  677. networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String()
  678. networkSettings.Networks[n.Name()].IPPrefixLen = ones
  679. }
  680. if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
  681. onesv6, _ := iface.AddressIPv6().Mask.Size()
  682. networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String()
  683. networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6
  684. }
  685. return nil
  686. }
  687. // UpdateJoinInfo updates network settings when container joins network n with endpoint ep.
  688. func (container *Container) UpdateJoinInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
  689. if err := container.buildPortMapInfo(ep); err != nil {
  690. return err
  691. }
  692. epInfo := ep.Info()
  693. if epInfo == nil {
  694. // It is not an error to get an empty endpoint info
  695. return nil
  696. }
  697. if epInfo.Gateway() != nil {
  698. container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
  699. }
  700. if epInfo.GatewayIPv6().To16() != nil {
  701. container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
  702. }
  703. return nil
  704. }
  705. // UpdateSandboxNetworkSettings updates the sandbox ID and Key.
  706. func (container *Container) UpdateSandboxNetworkSettings(sb libnetwork.Sandbox) error {
  707. container.NetworkSettings.SandboxID = sb.ID()
  708. container.NetworkSettings.SandboxKey = sb.Key()
  709. return nil
  710. }
  711. // BuildJoinOptions builds endpoint Join options from a given network.
  712. func (container *Container) BuildJoinOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) {
  713. var joinOptions []libnetwork.EndpointOption
  714. if epConfig, ok := container.NetworkSettings.Networks[n.Name()]; ok {
  715. for _, str := range epConfig.Links {
  716. name, alias, err := runconfigopts.ParseLink(str)
  717. if err != nil {
  718. return nil, err
  719. }
  720. joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias))
  721. }
  722. }
  723. return joinOptions, nil
  724. }
  725. // BuildCreateEndpointOptions builds endpoint options from a given network.
  726. func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *networktypes.EndpointSettings, sb libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) {
  727. var (
  728. bindings = make(nat.PortMap)
  729. pbList []types.PortBinding
  730. exposeList []types.TransportPort
  731. createOptions []libnetwork.EndpointOption
  732. )
  733. defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
  734. if (!container.EnableServiceDiscoveryOnDefaultNetwork() && n.Name() == defaultNetName) ||
  735. container.NetworkSettings.IsAnonymousEndpoint {
  736. createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
  737. }
  738. if epConfig != nil {
  739. ipam := epConfig.IPAMConfig
  740. if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "" || len(ipam.LinkLocalIPs) > 0) {
  741. var ipList []net.IP
  742. for _, ips := range ipam.LinkLocalIPs {
  743. if ip := net.ParseIP(ips); ip != nil {
  744. ipList = append(ipList, ip)
  745. }
  746. }
  747. createOptions = append(createOptions,
  748. libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), ipList, nil))
  749. }
  750. for _, alias := range epConfig.Aliases {
  751. createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias))
  752. }
  753. }
  754. if container.NetworkSettings.Service != nil {
  755. svcCfg := container.NetworkSettings.Service
  756. var vip string
  757. if svcCfg.VirtualAddresses[n.ID()] != nil {
  758. vip = svcCfg.VirtualAddresses[n.ID()].IPv4
  759. }
  760. var portConfigs []*libnetwork.PortConfig
  761. for _, portConfig := range svcCfg.ExposedPorts {
  762. portConfigs = append(portConfigs, &libnetwork.PortConfig{
  763. Name: portConfig.Name,
  764. Protocol: libnetwork.PortConfig_Protocol(portConfig.Protocol),
  765. TargetPort: portConfig.TargetPort,
  766. PublishedPort: portConfig.PublishedPort,
  767. })
  768. }
  769. createOptions = append(createOptions, libnetwork.CreateOptionService(svcCfg.Name, svcCfg.ID, net.ParseIP(vip), portConfigs, svcCfg.Aliases[n.ID()]))
  770. }
  771. if !containertypes.NetworkMode(n.Name()).IsUserDefined() {
  772. createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
  773. }
  774. // configs that are applicable only for the endpoint in the network
  775. // to which container was connected to on docker run.
  776. // Ideally all these network-specific endpoint configurations must be moved under
  777. // container.NetworkSettings.Networks[n.Name()]
  778. if n.Name() == container.HostConfig.NetworkMode.NetworkName() ||
  779. (n.Name() == defaultNetName && container.HostConfig.NetworkMode.IsDefault()) {
  780. if container.Config.MacAddress != "" {
  781. mac, err := net.ParseMAC(container.Config.MacAddress)
  782. if err != nil {
  783. return nil, err
  784. }
  785. genericOption := options.Generic{
  786. netlabel.MacAddress: mac,
  787. }
  788. createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
  789. }
  790. }
  791. // Port-mapping rules belong to the container & applicable only to non-internal networks
  792. portmaps := GetSandboxPortMapInfo(sb)
  793. if n.Info().Internal() || len(portmaps) > 0 {
  794. return createOptions, nil
  795. }
  796. if container.HostConfig.PortBindings != nil {
  797. for p, b := range container.HostConfig.PortBindings {
  798. bindings[p] = []nat.PortBinding{}
  799. for _, bb := range b {
  800. bindings[p] = append(bindings[p], nat.PortBinding{
  801. HostIP: bb.HostIP,
  802. HostPort: bb.HostPort,
  803. })
  804. }
  805. }
  806. }
  807. portSpecs := container.Config.ExposedPorts
  808. ports := make([]nat.Port, len(portSpecs))
  809. var i int
  810. for p := range portSpecs {
  811. ports[i] = p
  812. i++
  813. }
  814. nat.SortPortMap(ports, bindings)
  815. for _, port := range ports {
  816. expose := types.TransportPort{}
  817. expose.Proto = types.ParseProtocol(port.Proto())
  818. expose.Port = uint16(port.Int())
  819. exposeList = append(exposeList, expose)
  820. pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
  821. binding := bindings[port]
  822. for i := 0; i < len(binding); i++ {
  823. pbCopy := pb.GetCopy()
  824. newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
  825. var portStart, portEnd int
  826. if err == nil {
  827. portStart, portEnd, err = newP.Range()
  828. }
  829. if err != nil {
  830. return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err)
  831. }
  832. pbCopy.HostPort = uint16(portStart)
  833. pbCopy.HostPortEnd = uint16(portEnd)
  834. pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
  835. pbList = append(pbList, pbCopy)
  836. }
  837. if container.HostConfig.PublishAllPorts && len(binding) == 0 {
  838. pbList = append(pbList, pb)
  839. }
  840. }
  841. var dns []string
  842. if len(container.HostConfig.DNS) > 0 {
  843. dns = container.HostConfig.DNS
  844. } else if len(daemonDNS) > 0 {
  845. dns = daemonDNS
  846. }
  847. if len(dns) > 0 {
  848. createOptions = append(createOptions,
  849. libnetwork.CreateOptionDNS(dns))
  850. }
  851. createOptions = append(createOptions,
  852. libnetwork.CreateOptionPortMapping(pbList),
  853. libnetwork.CreateOptionExposedPorts(exposeList))
  854. return createOptions, nil
  855. }
  856. // UpdateMonitor updates monitor configure for running container
  857. func (container *Container) UpdateMonitor(restartPolicy containertypes.RestartPolicy) {
  858. type policySetter interface {
  859. SetPolicy(containertypes.RestartPolicy)
  860. }
  861. if rm, ok := container.RestartManager().(policySetter); ok {
  862. rm.SetPolicy(restartPolicy)
  863. }
  864. }
  865. // FullHostname returns hostname and optional domain appended to it.
  866. func (container *Container) FullHostname() string {
  867. fullHostname := container.Config.Hostname
  868. if container.Config.Domainname != "" {
  869. fullHostname = fmt.Sprintf("%s.%s", fullHostname, container.Config.Domainname)
  870. }
  871. return fullHostname
  872. }
  873. // RestartManager returns the current restartmanager instance connected to container.
  874. func (container *Container) RestartManager() restartmanager.RestartManager {
  875. if container.restartManager == nil {
  876. container.restartManager = restartmanager.New(container.HostConfig.RestartPolicy, container.RestartCount)
  877. }
  878. return container.restartManager
  879. }
  880. // ResetRestartManager initializes new restartmanager based on container config
  881. func (container *Container) ResetRestartManager(resetCount bool) {
  882. if container.restartManager != nil {
  883. container.restartManager.Cancel()
  884. }
  885. if resetCount {
  886. container.RestartCount = 0
  887. }
  888. container.restartManager = nil
  889. }
  890. type attachContext struct {
  891. ctx context.Context
  892. cancel context.CancelFunc
  893. mu sync.Mutex
  894. }
  895. // InitAttachContext initializes or returns existing context for attach calls to
  896. // track container liveness.
  897. func (container *Container) InitAttachContext() context.Context {
  898. container.attachContext.mu.Lock()
  899. defer container.attachContext.mu.Unlock()
  900. if container.attachContext.ctx == nil {
  901. container.attachContext.ctx, container.attachContext.cancel = context.WithCancel(context.Background())
  902. }
  903. return container.attachContext.ctx
  904. }
  905. // CancelAttachContext cancels attach context. All attach calls should detach
  906. // after this call.
  907. func (container *Container) CancelAttachContext() {
  908. container.attachContext.mu.Lock()
  909. if container.attachContext.ctx != nil {
  910. container.attachContext.cancel()
  911. container.attachContext.ctx = nil
  912. }
  913. container.attachContext.mu.Unlock()
  914. }
  915. func (container *Container) startLogging() error {
  916. if container.HostConfig.LogConfig.Type == "none" {
  917. return nil // do not start logging routines
  918. }
  919. l, err := container.StartLogger(container.HostConfig.LogConfig)
  920. if err != nil {
  921. return fmt.Errorf("Failed to initialize logging driver: %v", err)
  922. }
  923. copier := logger.NewCopier(map[string]io.Reader{"stdout": container.StdoutPipe(), "stderr": container.StderrPipe()}, l)
  924. container.LogCopier = copier
  925. copier.Run()
  926. container.LogDriver = l
  927. // set LogPath field only for json-file logdriver
  928. if jl, ok := l.(*jsonfilelog.JSONFileLogger); ok {
  929. container.LogPath = jl.LogPath()
  930. }
  931. return nil
  932. }
  933. // StdinPipe gets the stdin stream of the container
  934. func (container *Container) StdinPipe() io.WriteCloser {
  935. return container.StreamConfig.StdinPipe()
  936. }
  937. // StdoutPipe gets the stdout stream of the container
  938. func (container *Container) StdoutPipe() io.ReadCloser {
  939. return container.StreamConfig.StdoutPipe()
  940. }
  941. // StderrPipe gets the stderr stream of the container
  942. func (container *Container) StderrPipe() io.ReadCloser {
  943. return container.StreamConfig.StderrPipe()
  944. }
  945. // CloseStreams closes the container's stdio streams
  946. func (container *Container) CloseStreams() error {
  947. return container.StreamConfig.CloseStreams()
  948. }
  949. // InitializeStdio is called by libcontainerd to connect the stdio.
  950. func (container *Container) InitializeStdio(iop libcontainerd.IOPipe) error {
  951. if err := container.startLogging(); err != nil {
  952. container.Reset(false)
  953. return err
  954. }
  955. container.StreamConfig.CopyToPipe(iop)
  956. if container.StreamConfig.Stdin() == nil && !container.Config.Tty {
  957. if iop.Stdin != nil {
  958. if err := iop.Stdin.Close(); err != nil {
  959. logrus.Warnf("error closing stdin: %+v", err)
  960. }
  961. }
  962. }
  963. return nil
  964. }