container.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. package daemon
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "os"
  8. "path/filepath"
  9. "sync"
  10. "syscall"
  11. "time"
  12. "github.com/opencontainers/runc/libcontainer/label"
  13. "github.com/Sirupsen/logrus"
  14. "github.com/docker/docker/daemon/execdriver"
  15. "github.com/docker/docker/daemon/logger"
  16. "github.com/docker/docker/daemon/logger/jsonfilelog"
  17. "github.com/docker/docker/daemon/network"
  18. derr "github.com/docker/docker/errors"
  19. "github.com/docker/docker/pkg/broadcaster"
  20. "github.com/docker/docker/pkg/fileutils"
  21. "github.com/docker/docker/pkg/ioutils"
  22. "github.com/docker/docker/pkg/mount"
  23. "github.com/docker/docker/pkg/nat"
  24. "github.com/docker/docker/pkg/promise"
  25. "github.com/docker/docker/pkg/signal"
  26. "github.com/docker/docker/pkg/symlink"
  27. "github.com/docker/docker/pkg/system"
  28. "github.com/docker/docker/runconfig"
  29. "github.com/docker/docker/volume"
  30. )
  31. var (
  32. // ErrRootFSReadOnly is returned when a container
  33. // rootfs is marked readonly.
  34. ErrRootFSReadOnly = errors.New("container rootfs is marked read-only")
  35. )
  36. type streamConfig struct {
  37. stdout *broadcaster.Unbuffered
  38. stderr *broadcaster.Unbuffered
  39. stdin io.ReadCloser
  40. stdinPipe io.WriteCloser
  41. }
  42. // CommonContainer holds the fields for a container which are
  43. // applicable across all platforms supported by the daemon.
  44. type CommonContainer struct {
  45. streamConfig
  46. // embed for Container to support states directly.
  47. *State `json:"State"` // Needed for remote api version <= 1.11
  48. root string // Path to the "home" of the container, including metadata.
  49. basefs string // Path to the graphdriver mountpoint
  50. ID string
  51. Created time.Time
  52. Path string
  53. Args []string
  54. Config *runconfig.Config
  55. ImageID string `json:"Image"`
  56. NetworkSettings *network.Settings
  57. LogPath string
  58. Name string
  59. Driver string
  60. // MountLabel contains the options for the 'mount' command
  61. MountLabel string
  62. ProcessLabel string
  63. RestartCount int
  64. HasBeenStartedBefore bool
  65. HasBeenManuallyStopped bool // used for unless-stopped restart policy
  66. MountPoints map[string]*volume.MountPoint
  67. hostConfig *runconfig.HostConfig
  68. command *execdriver.Command
  69. monitor *containerMonitor
  70. execCommands *execStore
  71. // logDriver for closing
  72. logDriver logger.Logger
  73. logCopier *logger.Copier
  74. }
  75. func (container *Container) fromDisk() error {
  76. pth, err := container.jsonPath()
  77. if err != nil {
  78. return err
  79. }
  80. jsonSource, err := os.Open(pth)
  81. if err != nil {
  82. return err
  83. }
  84. defer jsonSource.Close()
  85. dec := json.NewDecoder(jsonSource)
  86. // Load container settings
  87. if err := dec.Decode(container); err != nil {
  88. return err
  89. }
  90. if err := label.ReserveLabel(container.ProcessLabel); err != nil {
  91. return err
  92. }
  93. return container.readHostConfig()
  94. }
  95. func (container *Container) toDisk() error {
  96. pth, err := container.jsonPath()
  97. if err != nil {
  98. return err
  99. }
  100. jsonSource, err := os.Create(pth)
  101. if err != nil {
  102. return err
  103. }
  104. defer jsonSource.Close()
  105. enc := json.NewEncoder(jsonSource)
  106. // Save container settings
  107. if err := enc.Encode(container); err != nil {
  108. return err
  109. }
  110. return container.writeHostConfig()
  111. }
  112. func (container *Container) toDiskLocking() error {
  113. container.Lock()
  114. err := container.toDisk()
  115. container.Unlock()
  116. return err
  117. }
  118. func (container *Container) readHostConfig() error {
  119. container.hostConfig = &runconfig.HostConfig{}
  120. // If the hostconfig file does not exist, do not read it.
  121. // (We still have to initialize container.hostConfig,
  122. // but that's OK, since we just did that above.)
  123. pth, err := container.hostConfigPath()
  124. if err != nil {
  125. return err
  126. }
  127. f, err := os.Open(pth)
  128. if err != nil {
  129. if os.IsNotExist(err) {
  130. return nil
  131. }
  132. return err
  133. }
  134. defer f.Close()
  135. return json.NewDecoder(f).Decode(&container.hostConfig)
  136. }
  137. func (container *Container) writeHostConfig() error {
  138. pth, err := container.hostConfigPath()
  139. if err != nil {
  140. return err
  141. }
  142. f, err := os.Create(pth)
  143. if err != nil {
  144. return err
  145. }
  146. defer f.Close()
  147. return json.NewEncoder(f).Encode(&container.hostConfig)
  148. }
  149. // GetResourcePath evaluates `path` in the scope of the container's basefs, with proper path
  150. // sanitisation. Symlinks are all scoped to the basefs of the container, as
  151. // though the container's basefs was `/`.
  152. //
  153. // The basefs of a container is the host-facing path which is bind-mounted as
  154. // `/` inside the container. This method is essentially used to access a
  155. // particular path inside the container as though you were a process in that
  156. // container.
  157. //
  158. // NOTE: The returned path is *only* safely scoped inside the container's basefs
  159. // if no component of the returned path changes (such as a component
  160. // symlinking to a different path) between using this method and using the
  161. // path. See symlink.FollowSymlinkInScope for more details.
  162. func (container *Container) GetResourcePath(path string) (string, error) {
  163. // IMPORTANT - These are paths on the OS where the daemon is running, hence
  164. // any filepath operations must be done in an OS agnostic way.
  165. cleanPath := filepath.Join(string(os.PathSeparator), path)
  166. r, e := symlink.FollowSymlinkInScope(filepath.Join(container.basefs, cleanPath), container.basefs)
  167. return r, e
  168. }
  169. // Evaluates `path` in the scope of the container's root, with proper path
  170. // sanitisation. Symlinks are all scoped to the root of the container, as
  171. // though the container's root was `/`.
  172. //
  173. // The root of a container is the host-facing configuration metadata directory.
  174. // Only use this method to safely access the container's `container.json` or
  175. // other metadata files. If in doubt, use container.GetResourcePath.
  176. //
  177. // NOTE: The returned path is *only* safely scoped inside the container's root
  178. // if no component of the returned path changes (such as a component
  179. // symlinking to a different path) between using this method and using the
  180. // path. See symlink.FollowSymlinkInScope for more details.
  181. func (container *Container) getRootResourcePath(path string) (string, error) {
  182. // IMPORTANT - These are paths on the OS where the daemon is running, hence
  183. // any filepath operations must be done in an OS agnostic way.
  184. cleanPath := filepath.Join(string(os.PathSeparator), path)
  185. return symlink.FollowSymlinkInScope(filepath.Join(container.root, cleanPath), container.root)
  186. }
  187. // streamConfig.StdinPipe returns a WriteCloser which can be used to feed data
  188. // to the standard input of the container's active process.
  189. // Container.StdoutPipe and Container.StderrPipe each return a ReadCloser
  190. // which can be used to retrieve the standard output (and error) generated
  191. // by the container's active process. The output (and error) are actually
  192. // copied and delivered to all StdoutPipe and StderrPipe consumers, using
  193. // a kind of "broadcaster".
  194. func (streamConfig *streamConfig) StdinPipe() io.WriteCloser {
  195. return streamConfig.stdinPipe
  196. }
  197. func (streamConfig *streamConfig) StdoutPipe() io.ReadCloser {
  198. reader, writer := io.Pipe()
  199. streamConfig.stdout.Add(writer)
  200. return ioutils.NewBufReader(reader)
  201. }
  202. func (streamConfig *streamConfig) StderrPipe() io.ReadCloser {
  203. reader, writer := io.Pipe()
  204. streamConfig.stderr.Add(writer)
  205. return ioutils.NewBufReader(reader)
  206. }
  207. // ExitOnNext signals to the monitor that it should not restart the container
  208. // after we send the kill signal.
  209. func (container *Container) ExitOnNext() {
  210. container.monitor.ExitOnNext()
  211. }
  212. // Resize changes the TTY of the process running inside the container
  213. // to the given height and width. The container must be running.
  214. func (container *Container) Resize(h, w int) error {
  215. if !container.IsRunning() {
  216. return derr.ErrorCodeNotRunning.WithArgs(container.ID)
  217. }
  218. if err := container.command.ProcessConfig.Terminal.Resize(h, w); err != nil {
  219. return err
  220. }
  221. return nil
  222. }
  223. func (container *Container) hostConfigPath() (string, error) {
  224. return container.getRootResourcePath("hostconfig.json")
  225. }
  226. func (container *Container) jsonPath() (string, error) {
  227. return container.getRootResourcePath("config.json")
  228. }
  229. // This directory is only usable when the container is running
  230. func (container *Container) rootfsPath() string {
  231. return container.basefs
  232. }
  233. func validateID(id string) error {
  234. if id == "" {
  235. return derr.ErrorCodeEmptyID
  236. }
  237. return nil
  238. }
  239. // Returns true if the container exposes a certain port
  240. func (container *Container) exposes(p nat.Port) bool {
  241. _, exists := container.Config.ExposedPorts[p]
  242. return exists
  243. }
  244. func (container *Container) getLogConfig(defaultConfig runconfig.LogConfig) runconfig.LogConfig {
  245. cfg := container.hostConfig.LogConfig
  246. if cfg.Type != "" || len(cfg.Config) > 0 { // container has log driver configured
  247. if cfg.Type == "" {
  248. cfg.Type = jsonfilelog.Name
  249. }
  250. return cfg
  251. }
  252. // Use daemon's default log config for containers
  253. return defaultConfig
  254. }
  255. // StartLogger starts a new logger driver for the container.
  256. func (container *Container) StartLogger(cfg runconfig.LogConfig) (logger.Logger, error) {
  257. c, err := logger.GetLogDriver(cfg.Type)
  258. if err != nil {
  259. return nil, derr.ErrorCodeLoggingFactory.WithArgs(err)
  260. }
  261. ctx := logger.Context{
  262. Config: cfg.Config,
  263. ContainerID: container.ID,
  264. ContainerName: container.Name,
  265. ContainerEntrypoint: container.Path,
  266. ContainerArgs: container.Args,
  267. ContainerImageID: container.ImageID,
  268. ContainerImageName: container.Config.Image,
  269. ContainerCreated: container.Created,
  270. ContainerEnv: container.Config.Env,
  271. ContainerLabels: container.Config.Labels,
  272. }
  273. // Set logging file for "json-logger"
  274. if cfg.Type == jsonfilelog.Name {
  275. ctx.LogPath, err = container.getRootResourcePath(fmt.Sprintf("%s-json.log", container.ID))
  276. if err != nil {
  277. return nil, err
  278. }
  279. }
  280. return c(ctx)
  281. }
  282. func (container *Container) getProcessLabel() string {
  283. // even if we have a process label return "" if we are running
  284. // in privileged mode
  285. if container.hostConfig.Privileged {
  286. return ""
  287. }
  288. return container.ProcessLabel
  289. }
  290. func (container *Container) getMountLabel() string {
  291. if container.hostConfig.Privileged {
  292. return ""
  293. }
  294. return container.MountLabel
  295. }
  296. func (container *Container) getExecIDs() []string {
  297. return container.execCommands.List()
  298. }
  299. // Attach connects to the container's TTY, delegating to standard
  300. // streams or websockets depending on the configuration.
  301. func (container *Container) Attach(stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) chan error {
  302. return attach(&container.streamConfig, container.Config.OpenStdin, container.Config.StdinOnce, container.Config.Tty, stdin, stdout, stderr)
  303. }
  304. func attach(streamConfig *streamConfig, openStdin, stdinOnce, tty bool, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) chan error {
  305. var (
  306. cStdout, cStderr io.ReadCloser
  307. cStdin io.WriteCloser
  308. wg sync.WaitGroup
  309. errors = make(chan error, 3)
  310. )
  311. if stdin != nil && openStdin {
  312. cStdin = streamConfig.StdinPipe()
  313. wg.Add(1)
  314. }
  315. if stdout != nil {
  316. cStdout = streamConfig.StdoutPipe()
  317. wg.Add(1)
  318. }
  319. if stderr != nil {
  320. cStderr = streamConfig.StderrPipe()
  321. wg.Add(1)
  322. }
  323. // Connect stdin of container to the http conn.
  324. go func() {
  325. if stdin == nil || !openStdin {
  326. return
  327. }
  328. logrus.Debugf("attach: stdin: begin")
  329. defer func() {
  330. if stdinOnce && !tty {
  331. cStdin.Close()
  332. } else {
  333. // No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
  334. if cStdout != nil {
  335. cStdout.Close()
  336. }
  337. if cStderr != nil {
  338. cStderr.Close()
  339. }
  340. }
  341. wg.Done()
  342. logrus.Debugf("attach: stdin: end")
  343. }()
  344. var err error
  345. if tty {
  346. _, err = copyEscapable(cStdin, stdin)
  347. } else {
  348. _, err = io.Copy(cStdin, stdin)
  349. }
  350. if err == io.ErrClosedPipe {
  351. err = nil
  352. }
  353. if err != nil {
  354. logrus.Errorf("attach: stdin: %s", err)
  355. errors <- err
  356. return
  357. }
  358. }()
  359. attachStream := func(name string, stream io.Writer, streamPipe io.ReadCloser) {
  360. if stream == nil {
  361. return
  362. }
  363. defer func() {
  364. // Make sure stdin gets closed
  365. if stdin != nil {
  366. stdin.Close()
  367. }
  368. streamPipe.Close()
  369. wg.Done()
  370. logrus.Debugf("attach: %s: end", name)
  371. }()
  372. logrus.Debugf("attach: %s: begin", name)
  373. _, err := io.Copy(stream, streamPipe)
  374. if err == io.ErrClosedPipe {
  375. err = nil
  376. }
  377. if err != nil {
  378. logrus.Errorf("attach: %s: %v", name, err)
  379. errors <- err
  380. }
  381. }
  382. go attachStream("stdout", stdout, cStdout)
  383. go attachStream("stderr", stderr, cStderr)
  384. return promise.Go(func() error {
  385. wg.Wait()
  386. close(errors)
  387. for err := range errors {
  388. if err != nil {
  389. return err
  390. }
  391. }
  392. return nil
  393. })
  394. }
  395. // Code c/c from io.Copy() modified to handle escape sequence
  396. func copyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error) {
  397. buf := make([]byte, 32*1024)
  398. for {
  399. nr, er := src.Read(buf)
  400. if nr > 0 {
  401. // ---- Docker addition
  402. // char 16 is C-p
  403. if nr == 1 && buf[0] == 16 {
  404. nr, er = src.Read(buf)
  405. // char 17 is C-q
  406. if nr == 1 && buf[0] == 17 {
  407. if err := src.Close(); err != nil {
  408. return 0, err
  409. }
  410. return 0, nil
  411. }
  412. }
  413. // ---- End of docker
  414. nw, ew := dst.Write(buf[0:nr])
  415. if nw > 0 {
  416. written += int64(nw)
  417. }
  418. if ew != nil {
  419. err = ew
  420. break
  421. }
  422. if nr != nw {
  423. err = io.ErrShortWrite
  424. break
  425. }
  426. }
  427. if er == io.EOF {
  428. break
  429. }
  430. if er != nil {
  431. err = er
  432. break
  433. }
  434. }
  435. return written, err
  436. }
  437. func (container *Container) shouldRestart() bool {
  438. return container.hostConfig.RestartPolicy.Name == "always" ||
  439. (container.hostConfig.RestartPolicy.Name == "unless-stopped" && !container.HasBeenManuallyStopped) ||
  440. (container.hostConfig.RestartPolicy.Name == "on-failure" && container.ExitCode != 0)
  441. }
  442. func (daemon *Daemon) mountVolumes(container *Container) error {
  443. mounts, err := daemon.setupMounts(container)
  444. if err != nil {
  445. return err
  446. }
  447. for _, m := range mounts {
  448. dest, err := container.GetResourcePath(m.Destination)
  449. if err != nil {
  450. return err
  451. }
  452. var stat os.FileInfo
  453. stat, err = os.Stat(m.Source)
  454. if err != nil {
  455. return err
  456. }
  457. if err = fileutils.CreateIfNotExists(dest, stat.IsDir()); err != nil {
  458. return err
  459. }
  460. opts := "rbind,ro"
  461. if m.Writable {
  462. opts = "rbind,rw"
  463. }
  464. if err := mount.Mount(m.Source, dest, "bind", opts); err != nil {
  465. return err
  466. }
  467. }
  468. return nil
  469. }
  470. func (container *Container) unmountVolumes(forceSyscall bool) error {
  471. var (
  472. volumeMounts []volume.MountPoint
  473. err error
  474. )
  475. for _, mntPoint := range container.MountPoints {
  476. dest, err := container.GetResourcePath(mntPoint.Destination)
  477. if err != nil {
  478. return err
  479. }
  480. volumeMounts = append(volumeMounts, volume.MountPoint{Destination: dest, Volume: mntPoint.Volume})
  481. }
  482. // Append any network mounts to the list (this is a no-op on Windows)
  483. if volumeMounts, err = appendNetworkMounts(container, volumeMounts); err != nil {
  484. return err
  485. }
  486. for _, volumeMount := range volumeMounts {
  487. if forceSyscall {
  488. if err := system.Unmount(volumeMount.Destination); err != nil {
  489. logrus.Warnf("%s unmountVolumes: Failed to force umount %v", container.ID, err)
  490. }
  491. }
  492. if volumeMount.Volume != nil {
  493. if err := volumeMount.Volume.Unmount(); err != nil {
  494. return err
  495. }
  496. }
  497. }
  498. return nil
  499. }
  500. func (container *Container) addBindMountPoint(name, source, destination string, rw bool) {
  501. container.MountPoints[destination] = &volume.MountPoint{
  502. Name: name,
  503. Source: source,
  504. Destination: destination,
  505. RW: rw,
  506. }
  507. }
  508. func (container *Container) addLocalMountPoint(name, destination string, rw bool) {
  509. container.MountPoints[destination] = &volume.MountPoint{
  510. Name: name,
  511. Driver: volume.DefaultDriverName,
  512. Destination: destination,
  513. RW: rw,
  514. }
  515. }
  516. func (container *Container) addMountPointWithVolume(destination string, vol volume.Volume, rw bool) {
  517. container.MountPoints[destination] = &volume.MountPoint{
  518. Name: vol.Name(),
  519. Driver: vol.DriverName(),
  520. Destination: destination,
  521. RW: rw,
  522. Volume: vol,
  523. }
  524. }
  525. func (container *Container) isDestinationMounted(destination string) bool {
  526. return container.MountPoints[destination] != nil
  527. }
  528. func (container *Container) stopSignal() int {
  529. var stopSignal syscall.Signal
  530. if container.Config.StopSignal != "" {
  531. stopSignal, _ = signal.ParseSignal(container.Config.StopSignal)
  532. }
  533. if int(stopSignal) == 0 {
  534. stopSignal, _ = signal.ParseSignal(signal.DefaultStopSignal)
  535. }
  536. return int(stopSignal)
  537. }