container.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182
  1. package runtime
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "github.com/dotcloud/docker/archive"
  7. "github.com/dotcloud/docker/engine"
  8. "github.com/dotcloud/docker/image"
  9. "github.com/dotcloud/docker/links"
  10. "github.com/dotcloud/docker/nat"
  11. "github.com/dotcloud/docker/runconfig"
  12. "github.com/dotcloud/docker/runtime/execdriver"
  13. "github.com/dotcloud/docker/runtime/graphdriver"
  14. "github.com/dotcloud/docker/utils"
  15. "io"
  16. "io/ioutil"
  17. "log"
  18. "os"
  19. "path"
  20. "strings"
  21. "sync"
  22. "syscall"
  23. "time"
  24. )
  25. const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
  26. var (
  27. ErrNotATTY = errors.New("The PTY is not a file")
  28. ErrNoTTY = errors.New("No PTY found")
  29. ErrContainerStart = errors.New("The container failed to start. Unknown error")
  30. ErrContainerStartTimeout = errors.New("The container failed to start due to timed out.")
  31. )
  32. type Container struct {
  33. sync.Mutex
  34. root string // Path to the "home" of the container, including metadata.
  35. basefs string // Path to the graphdriver mountpoint
  36. ID string
  37. Created time.Time
  38. Path string
  39. Args []string
  40. Config *runconfig.Config
  41. State State
  42. Image string
  43. NetworkSettings *NetworkSettings
  44. ResolvConfPath string
  45. HostnamePath string
  46. HostsPath string
  47. Name string
  48. Driver string
  49. ExecDriver string
  50. command *execdriver.Command
  51. stdout *utils.WriteBroadcaster
  52. stderr *utils.WriteBroadcaster
  53. stdin io.ReadCloser
  54. stdinPipe io.WriteCloser
  55. runtime *Runtime
  56. waitLock chan struct{}
  57. Volumes map[string]string
  58. // Store rw/ro in a separate structure to preserve reverse-compatibility on-disk.
  59. // Easier than migrating older container configs :)
  60. VolumesRW map[string]bool
  61. hostConfig *runconfig.HostConfig
  62. activeLinks map[string]*links.Link
  63. }
  64. // FIXME: move deprecated port stuff to nat to clean up the core.
  65. type PortMapping map[string]string // Deprecated
  66. type NetworkSettings struct {
  67. IPAddress string
  68. IPPrefixLen int
  69. Gateway string
  70. Bridge string
  71. PortMapping map[string]PortMapping // Deprecated
  72. Ports nat.PortMap
  73. }
  74. func (settings *NetworkSettings) PortMappingAPI() *engine.Table {
  75. var outs = engine.NewTable("", 0)
  76. for port, bindings := range settings.Ports {
  77. p, _ := nat.ParsePort(port.Port())
  78. if len(bindings) == 0 {
  79. out := &engine.Env{}
  80. out.SetInt("PublicPort", p)
  81. out.Set("Type", port.Proto())
  82. outs.Add(out)
  83. continue
  84. }
  85. for _, binding := range bindings {
  86. out := &engine.Env{}
  87. h, _ := nat.ParsePort(binding.HostPort)
  88. out.SetInt("PrivatePort", p)
  89. out.SetInt("PublicPort", h)
  90. out.Set("Type", port.Proto())
  91. out.Set("IP", binding.HostIp)
  92. outs.Add(out)
  93. }
  94. }
  95. return outs
  96. }
  97. // Inject the io.Reader at the given path. Note: do not close the reader
  98. func (container *Container) Inject(file io.Reader, pth string) error {
  99. if err := container.Mount(); err != nil {
  100. return fmt.Errorf("inject: error mounting container %s: %s", container.ID, err)
  101. }
  102. defer container.Unmount()
  103. // Return error if path exists
  104. destPath := path.Join(container.basefs, pth)
  105. if _, err := os.Stat(destPath); err == nil {
  106. // Since err is nil, the path could be stat'd and it exists
  107. return fmt.Errorf("%s exists", pth)
  108. } else if !os.IsNotExist(err) {
  109. // Expect err might be that the file doesn't exist, so
  110. // if it's some other error, return that.
  111. return err
  112. }
  113. // Make sure the directory exists
  114. if err := os.MkdirAll(path.Join(container.basefs, path.Dir(pth)), 0755); err != nil {
  115. return err
  116. }
  117. dest, err := os.Create(destPath)
  118. if err != nil {
  119. return err
  120. }
  121. defer dest.Close()
  122. if _, err := io.Copy(dest, file); err != nil {
  123. return err
  124. }
  125. return nil
  126. }
  127. func (container *Container) When() time.Time {
  128. return container.Created
  129. }
  130. func (container *Container) FromDisk() error {
  131. data, err := ioutil.ReadFile(container.jsonPath())
  132. if err != nil {
  133. return err
  134. }
  135. // Load container settings
  136. // udp broke compat of docker.PortMapping, but it's not used when loading a container, we can skip it
  137. if err := json.Unmarshal(data, container); err != nil && !strings.Contains(err.Error(), "docker.PortMapping") {
  138. return err
  139. }
  140. return container.readHostConfig()
  141. }
  142. func (container *Container) ToDisk() (err error) {
  143. data, err := json.Marshal(container)
  144. if err != nil {
  145. return
  146. }
  147. err = ioutil.WriteFile(container.jsonPath(), data, 0666)
  148. if err != nil {
  149. return
  150. }
  151. return container.WriteHostConfig()
  152. }
  153. func (container *Container) readHostConfig() error {
  154. container.hostConfig = &runconfig.HostConfig{}
  155. // If the hostconfig file does not exist, do not read it.
  156. // (We still have to initialize container.hostConfig,
  157. // but that's OK, since we just did that above.)
  158. _, err := os.Stat(container.hostConfigPath())
  159. if os.IsNotExist(err) {
  160. return nil
  161. }
  162. data, err := ioutil.ReadFile(container.hostConfigPath())
  163. if err != nil {
  164. return err
  165. }
  166. return json.Unmarshal(data, container.hostConfig)
  167. }
  168. func (container *Container) WriteHostConfig() (err error) {
  169. data, err := json.Marshal(container.hostConfig)
  170. if err != nil {
  171. return
  172. }
  173. return ioutil.WriteFile(container.hostConfigPath(), data, 0666)
  174. }
  175. func (container *Container) generateEnvConfig(env []string) error {
  176. data, err := json.Marshal(env)
  177. if err != nil {
  178. return err
  179. }
  180. p, err := container.EnvConfigPath()
  181. if err != nil {
  182. return err
  183. }
  184. ioutil.WriteFile(p, data, 0600)
  185. return nil
  186. }
  187. func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
  188. var cStdout, cStderr io.ReadCloser
  189. var nJobs int
  190. errors := make(chan error, 3)
  191. if stdin != nil && container.Config.OpenStdin {
  192. nJobs += 1
  193. if cStdin, err := container.StdinPipe(); err != nil {
  194. errors <- err
  195. } else {
  196. go func() {
  197. utils.Debugf("attach: stdin: begin")
  198. defer utils.Debugf("attach: stdin: end")
  199. // No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
  200. if container.Config.StdinOnce && !container.Config.Tty {
  201. defer cStdin.Close()
  202. } else {
  203. defer func() {
  204. if cStdout != nil {
  205. cStdout.Close()
  206. }
  207. if cStderr != nil {
  208. cStderr.Close()
  209. }
  210. }()
  211. }
  212. if container.Config.Tty {
  213. _, err = utils.CopyEscapable(cStdin, stdin)
  214. } else {
  215. _, err = io.Copy(cStdin, stdin)
  216. }
  217. if err == io.ErrClosedPipe {
  218. err = nil
  219. }
  220. if err != nil {
  221. utils.Errorf("attach: stdin: %s", err)
  222. }
  223. errors <- err
  224. }()
  225. }
  226. }
  227. if stdout != nil {
  228. nJobs += 1
  229. if p, err := container.StdoutPipe(); err != nil {
  230. errors <- err
  231. } else {
  232. cStdout = p
  233. go func() {
  234. utils.Debugf("attach: stdout: begin")
  235. defer utils.Debugf("attach: stdout: end")
  236. // If we are in StdinOnce mode, then close stdin
  237. if container.Config.StdinOnce && stdin != nil {
  238. defer stdin.Close()
  239. }
  240. if stdinCloser != nil {
  241. defer stdinCloser.Close()
  242. }
  243. _, err := io.Copy(stdout, cStdout)
  244. if err == io.ErrClosedPipe {
  245. err = nil
  246. }
  247. if err != nil {
  248. utils.Errorf("attach: stdout: %s", err)
  249. }
  250. errors <- err
  251. }()
  252. }
  253. } else {
  254. go func() {
  255. if stdinCloser != nil {
  256. defer stdinCloser.Close()
  257. }
  258. if cStdout, err := container.StdoutPipe(); err != nil {
  259. utils.Errorf("attach: stdout pipe: %s", err)
  260. } else {
  261. io.Copy(&utils.NopWriter{}, cStdout)
  262. }
  263. }()
  264. }
  265. if stderr != nil {
  266. nJobs += 1
  267. if p, err := container.StderrPipe(); err != nil {
  268. errors <- err
  269. } else {
  270. cStderr = p
  271. go func() {
  272. utils.Debugf("attach: stderr: begin")
  273. defer utils.Debugf("attach: stderr: end")
  274. // If we are in StdinOnce mode, then close stdin
  275. if container.Config.StdinOnce && stdin != nil {
  276. defer stdin.Close()
  277. }
  278. if stdinCloser != nil {
  279. defer stdinCloser.Close()
  280. }
  281. _, err := io.Copy(stderr, cStderr)
  282. if err == io.ErrClosedPipe {
  283. err = nil
  284. }
  285. if err != nil {
  286. utils.Errorf("attach: stderr: %s", err)
  287. }
  288. errors <- err
  289. }()
  290. }
  291. } else {
  292. go func() {
  293. if stdinCloser != nil {
  294. defer stdinCloser.Close()
  295. }
  296. if cStderr, err := container.StderrPipe(); err != nil {
  297. utils.Errorf("attach: stdout pipe: %s", err)
  298. } else {
  299. io.Copy(&utils.NopWriter{}, cStderr)
  300. }
  301. }()
  302. }
  303. return utils.Go(func() error {
  304. defer func() {
  305. if cStdout != nil {
  306. cStdout.Close()
  307. }
  308. if cStderr != nil {
  309. cStderr.Close()
  310. }
  311. }()
  312. // FIXME: how to clean up the stdin goroutine without the unwanted side effect
  313. // of closing the passed stdin? Add an intermediary io.Pipe?
  314. for i := 0; i < nJobs; i += 1 {
  315. utils.Debugf("attach: waiting for job %d/%d", i+1, nJobs)
  316. if err := <-errors; err != nil {
  317. utils.Errorf("attach: job %d returned error %s, aborting all jobs", i+1, err)
  318. return err
  319. }
  320. utils.Debugf("attach: job %d completed successfully", i+1)
  321. }
  322. utils.Debugf("attach: all jobs completed successfully")
  323. return nil
  324. })
  325. }
  326. func populateCommand(c *Container) {
  327. var (
  328. en *execdriver.Network
  329. driverConfig = c.hostConfig.DriverOptions
  330. )
  331. if driverConfig == nil {
  332. driverConfig = make(map[string][]string)
  333. }
  334. en = &execdriver.Network{
  335. Mtu: c.runtime.config.Mtu,
  336. Interface: nil,
  337. }
  338. if !c.Config.NetworkDisabled {
  339. network := c.NetworkSettings
  340. en.Interface = &execdriver.NetworkInterface{
  341. Gateway: network.Gateway,
  342. Bridge: network.Bridge,
  343. IPAddress: network.IPAddress,
  344. IPPrefixLen: network.IPPrefixLen,
  345. }
  346. }
  347. // TODO: this can be removed after lxc-conf is fully deprecated
  348. mergeLxcConfIntoOptions(c.hostConfig, driverConfig)
  349. resources := &execdriver.Resources{
  350. Memory: c.Config.Memory,
  351. MemorySwap: c.Config.MemorySwap,
  352. CpuShares: c.Config.CpuShares,
  353. }
  354. c.command = &execdriver.Command{
  355. ID: c.ID,
  356. Privileged: c.hostConfig.Privileged,
  357. Rootfs: c.RootfsPath(),
  358. InitPath: "/.dockerinit",
  359. Entrypoint: c.Path,
  360. Arguments: c.Args,
  361. WorkingDir: c.Config.WorkingDir,
  362. Network: en,
  363. Tty: c.Config.Tty,
  364. User: c.Config.User,
  365. Config: driverConfig,
  366. Resources: resources,
  367. Context: c.Config.Context,
  368. }
  369. c.command.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
  370. }
  371. func (container *Container) ArgsAsString() string {
  372. var args []string
  373. for _, arg := range container.Args {
  374. if strings.Contains(arg, " ") {
  375. args = append(args, fmt.Sprintf("'%s'", arg))
  376. } else {
  377. args = append(args, arg)
  378. }
  379. }
  380. return strings.Join(args, " ")
  381. }
  382. func (container *Container) Start() (err error) {
  383. container.Lock()
  384. defer container.Unlock()
  385. if container.State.IsRunning() {
  386. return nil
  387. }
  388. defer func() {
  389. if err != nil {
  390. container.cleanup()
  391. }
  392. }()
  393. if err := container.Mount(); err != nil {
  394. return err
  395. }
  396. if container.runtime.config.DisableNetwork {
  397. container.Config.NetworkDisabled = true
  398. container.buildHostnameAndHostsFiles("127.0.1.1")
  399. } else {
  400. if err := container.allocateNetwork(); err != nil {
  401. return err
  402. }
  403. container.buildHostnameAndHostsFiles(container.NetworkSettings.IPAddress)
  404. }
  405. // Make sure the config is compatible with the current kernel
  406. if container.Config.Memory > 0 && !container.runtime.sysInfo.MemoryLimit {
  407. log.Printf("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
  408. container.Config.Memory = 0
  409. }
  410. if container.Config.Memory > 0 && !container.runtime.sysInfo.SwapLimit {
  411. log.Printf("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
  412. container.Config.MemorySwap = -1
  413. }
  414. if container.runtime.sysInfo.IPv4ForwardingDisabled {
  415. log.Printf("WARNING: IPv4 forwarding is disabled. Networking will not work")
  416. }
  417. if err := prepareVolumesForContainer(container); err != nil {
  418. return err
  419. }
  420. // Setup environment
  421. env := []string{
  422. "HOME=/",
  423. "PATH=" + DefaultPathEnv,
  424. "HOSTNAME=" + container.Config.Hostname,
  425. }
  426. if container.Config.Tty {
  427. env = append(env, "TERM=xterm")
  428. }
  429. // Init any links between the parent and children
  430. runtime := container.runtime
  431. children, err := runtime.Children(container.Name)
  432. if err != nil {
  433. return err
  434. }
  435. if len(children) > 0 {
  436. container.activeLinks = make(map[string]*links.Link, len(children))
  437. // If we encounter an error make sure that we rollback any network
  438. // config and ip table changes
  439. rollback := func() {
  440. for _, link := range container.activeLinks {
  441. link.Disable()
  442. }
  443. container.activeLinks = nil
  444. }
  445. for linkAlias, child := range children {
  446. if !child.State.IsRunning() {
  447. return fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias)
  448. }
  449. link, err := links.NewLink(
  450. container.NetworkSettings.IPAddress,
  451. child.NetworkSettings.IPAddress,
  452. linkAlias,
  453. child.Config.Env,
  454. child.Config.ExposedPorts,
  455. runtime.eng)
  456. if err != nil {
  457. rollback()
  458. return err
  459. }
  460. container.activeLinks[link.Alias()] = link
  461. if err := link.Enable(); err != nil {
  462. rollback()
  463. return err
  464. }
  465. for _, envVar := range link.ToEnv() {
  466. env = append(env, envVar)
  467. }
  468. }
  469. }
  470. // because the env on the container can override certain default values
  471. // we need to replace the 'env' keys where they match and append anything
  472. // else.
  473. env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env)
  474. if err := container.generateEnvConfig(env); err != nil {
  475. return err
  476. }
  477. if container.Config.WorkingDir != "" {
  478. container.Config.WorkingDir = path.Clean(container.Config.WorkingDir)
  479. pthInfo, err := os.Stat(path.Join(container.basefs, container.Config.WorkingDir))
  480. if err != nil {
  481. if !os.IsNotExist(err) {
  482. return err
  483. }
  484. if err := os.MkdirAll(path.Join(container.basefs, container.Config.WorkingDir), 0755); err != nil {
  485. return err
  486. }
  487. }
  488. if pthInfo != nil && !pthInfo.IsDir() {
  489. return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)
  490. }
  491. }
  492. envPath, err := container.EnvConfigPath()
  493. if err != nil {
  494. return err
  495. }
  496. populateCommand(container)
  497. container.command.Env = env
  498. if err := setupMountsForContainer(container, envPath); err != nil {
  499. return err
  500. }
  501. // Setup logging of stdout and stderr to disk
  502. if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
  503. return err
  504. }
  505. if err := container.runtime.LogToDisk(container.stderr, container.logPath("json"), "stderr"); err != nil {
  506. return err
  507. }
  508. container.waitLock = make(chan struct{})
  509. callbackLock := make(chan struct{})
  510. callback := func(command *execdriver.Command) {
  511. container.State.SetRunning(command.Pid())
  512. if command.Tty {
  513. // The callback is called after the process Start()
  514. // so we are in the parent process. In TTY mode, stdin/out/err is the PtySlace
  515. // which we close here.
  516. if c, ok := command.Stdout.(io.Closer); ok {
  517. c.Close()
  518. }
  519. }
  520. if err := container.ToDisk(); err != nil {
  521. utils.Debugf("%s", err)
  522. }
  523. close(callbackLock)
  524. }
  525. // We use a callback here instead of a goroutine and an chan for
  526. // syncronization purposes
  527. cErr := utils.Go(func() error { return container.monitor(callback) })
  528. // Start should not return until the process is actually running
  529. select {
  530. case <-callbackLock:
  531. case err := <-cErr:
  532. return err
  533. }
  534. return nil
  535. }
  536. func (container *Container) Run() error {
  537. if err := container.Start(); err != nil {
  538. return err
  539. }
  540. container.Wait()
  541. return nil
  542. }
  543. func (container *Container) Output() (output []byte, err error) {
  544. pipe, err := container.StdoutPipe()
  545. if err != nil {
  546. return nil, err
  547. }
  548. defer pipe.Close()
  549. if err := container.Start(); err != nil {
  550. return nil, err
  551. }
  552. output, err = ioutil.ReadAll(pipe)
  553. container.Wait()
  554. return output, err
  555. }
  556. // Container.StdinPipe returns a WriteCloser which can be used to feed data
  557. // to the standard input of the container's active process.
  558. // Container.StdoutPipe and Container.StderrPipe each return a ReadCloser
  559. // which can be used to retrieve the standard output (and error) generated
  560. // by the container's active process. The output (and error) are actually
  561. // copied and delivered to all StdoutPipe and StderrPipe consumers, using
  562. // a kind of "broadcaster".
  563. func (container *Container) StdinPipe() (io.WriteCloser, error) {
  564. return container.stdinPipe, nil
  565. }
  566. func (container *Container) StdoutPipe() (io.ReadCloser, error) {
  567. reader, writer := io.Pipe()
  568. container.stdout.AddWriter(writer, "")
  569. return utils.NewBufReader(reader), nil
  570. }
  571. func (container *Container) StderrPipe() (io.ReadCloser, error) {
  572. reader, writer := io.Pipe()
  573. container.stderr.AddWriter(writer, "")
  574. return utils.NewBufReader(reader), nil
  575. }
  576. func (container *Container) buildHostnameAndHostsFiles(IP string) {
  577. container.HostnamePath = path.Join(container.root, "hostname")
  578. ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
  579. hostsContent := []byte(`
  580. 127.0.0.1 localhost
  581. ::1 localhost ip6-localhost ip6-loopback
  582. fe00::0 ip6-localnet
  583. ff00::0 ip6-mcastprefix
  584. ff02::1 ip6-allnodes
  585. ff02::2 ip6-allrouters
  586. `)
  587. container.HostsPath = path.Join(container.root, "hosts")
  588. if container.Config.Domainname != "" {
  589. hostsContent = append([]byte(fmt.Sprintf("%s\t%s.%s %s\n", IP, container.Config.Hostname, container.Config.Domainname, container.Config.Hostname)), hostsContent...)
  590. } else if !container.Config.NetworkDisabled {
  591. hostsContent = append([]byte(fmt.Sprintf("%s\t%s\n", IP, container.Config.Hostname)), hostsContent...)
  592. }
  593. ioutil.WriteFile(container.HostsPath, hostsContent, 0644)
  594. }
  595. func (container *Container) allocateNetwork() error {
  596. if container.Config.NetworkDisabled {
  597. return nil
  598. }
  599. var (
  600. env *engine.Env
  601. err error
  602. eng = container.runtime.eng
  603. )
  604. if container.State.IsGhost() {
  605. if container.runtime.config.DisableNetwork {
  606. env = &engine.Env{}
  607. } else {
  608. currentIP := container.NetworkSettings.IPAddress
  609. job := eng.Job("allocate_interface", container.ID)
  610. if currentIP != "" {
  611. job.Setenv("RequestIP", currentIP)
  612. }
  613. env, err = job.Stdout.AddEnv()
  614. if err != nil {
  615. return err
  616. }
  617. if err := job.Run(); err != nil {
  618. return err
  619. }
  620. }
  621. } else {
  622. job := eng.Job("allocate_interface", container.ID)
  623. env, err = job.Stdout.AddEnv()
  624. if err != nil {
  625. return err
  626. }
  627. if err := job.Run(); err != nil {
  628. return err
  629. }
  630. }
  631. if container.Config.PortSpecs != nil {
  632. utils.Debugf("Migrating port mappings for container: %s", strings.Join(container.Config.PortSpecs, ", "))
  633. if err := migratePortMappings(container.Config, container.hostConfig); err != nil {
  634. return err
  635. }
  636. container.Config.PortSpecs = nil
  637. if err := container.WriteHostConfig(); err != nil {
  638. return err
  639. }
  640. }
  641. var (
  642. portSpecs = make(nat.PortSet)
  643. bindings = make(nat.PortMap)
  644. )
  645. if !container.State.IsGhost() {
  646. if container.Config.ExposedPorts != nil {
  647. portSpecs = container.Config.ExposedPorts
  648. }
  649. if container.hostConfig.PortBindings != nil {
  650. bindings = container.hostConfig.PortBindings
  651. }
  652. } else {
  653. if container.NetworkSettings.Ports != nil {
  654. for port, binding := range container.NetworkSettings.Ports {
  655. portSpecs[port] = struct{}{}
  656. bindings[port] = binding
  657. }
  658. }
  659. }
  660. container.NetworkSettings.PortMapping = nil
  661. for port := range portSpecs {
  662. binding := bindings[port]
  663. if container.hostConfig.PublishAllPorts && len(binding) == 0 {
  664. binding = append(binding, nat.PortBinding{})
  665. }
  666. for i := 0; i < len(binding); i++ {
  667. b := binding[i]
  668. portJob := eng.Job("allocate_port", container.ID)
  669. portJob.Setenv("HostIP", b.HostIp)
  670. portJob.Setenv("HostPort", b.HostPort)
  671. portJob.Setenv("Proto", port.Proto())
  672. portJob.Setenv("ContainerPort", port.Port())
  673. portEnv, err := portJob.Stdout.AddEnv()
  674. if err != nil {
  675. return err
  676. }
  677. if err := portJob.Run(); err != nil {
  678. eng.Job("release_interface", container.ID).Run()
  679. return err
  680. }
  681. b.HostIp = portEnv.Get("HostIP")
  682. b.HostPort = portEnv.Get("HostPort")
  683. binding[i] = b
  684. }
  685. bindings[port] = binding
  686. }
  687. container.WriteHostConfig()
  688. container.NetworkSettings.Ports = bindings
  689. container.NetworkSettings.Bridge = env.Get("Bridge")
  690. container.NetworkSettings.IPAddress = env.Get("IP")
  691. container.NetworkSettings.IPPrefixLen = env.GetInt("IPPrefixLen")
  692. container.NetworkSettings.Gateway = env.Get("Gateway")
  693. return nil
  694. }
  695. func (container *Container) releaseNetwork() {
  696. if container.Config.NetworkDisabled {
  697. return
  698. }
  699. eng := container.runtime.eng
  700. eng.Job("release_interface", container.ID).Run()
  701. container.NetworkSettings = &NetworkSettings{}
  702. }
  703. func (container *Container) monitor(callback execdriver.StartCallback) error {
  704. var (
  705. err error
  706. exitCode int
  707. )
  708. pipes := execdriver.NewPipes(container.stdin, container.stdout, container.stderr, container.Config.OpenStdin)
  709. exitCode, err = container.runtime.Run(container, pipes, callback)
  710. if err != nil {
  711. utils.Errorf("Error running container: %s", err)
  712. }
  713. if container.runtime != nil && container.runtime.srv != nil && container.runtime.srv.IsRunning() {
  714. container.State.SetStopped(exitCode)
  715. // FIXME: there is a race condition here which causes this to fail during the unit tests.
  716. // If another goroutine was waiting for Wait() to return before removing the container's root
  717. // from the filesystem... At this point it may already have done so.
  718. // This is because State.setStopped() has already been called, and has caused Wait()
  719. // to return.
  720. // FIXME: why are we serializing running state to disk in the first place?
  721. //log.Printf("%s: Failed to dump configuration to the disk: %s", container.ID, err)
  722. if err := container.ToDisk(); err != nil {
  723. utils.Errorf("Error dumping container state to disk: %s\n", err)
  724. }
  725. }
  726. // Cleanup
  727. container.cleanup()
  728. // Re-create a brand new stdin pipe once the container exited
  729. if container.Config.OpenStdin {
  730. container.stdin, container.stdinPipe = io.Pipe()
  731. }
  732. if container.runtime != nil && container.runtime.srv != nil {
  733. container.runtime.srv.LogEvent("die", container.ID, container.runtime.repositories.ImageName(container.Image))
  734. }
  735. close(container.waitLock)
  736. return err
  737. }
  738. func (container *Container) cleanup() {
  739. container.releaseNetwork()
  740. // Disable all active links
  741. if container.activeLinks != nil {
  742. for _, link := range container.activeLinks {
  743. link.Disable()
  744. }
  745. }
  746. if container.Config.OpenStdin {
  747. if err := container.stdin.Close(); err != nil {
  748. utils.Errorf("%s: Error close stdin: %s", container.ID, err)
  749. }
  750. }
  751. if err := container.stdout.CloseWriters(); err != nil {
  752. utils.Errorf("%s: Error close stdout: %s", container.ID, err)
  753. }
  754. if err := container.stderr.CloseWriters(); err != nil {
  755. utils.Errorf("%s: Error close stderr: %s", container.ID, err)
  756. }
  757. if container.command != nil && container.command.Terminal != nil {
  758. if err := container.command.Terminal.Close(); err != nil {
  759. utils.Errorf("%s: Error closing terminal: %s", container.ID, err)
  760. }
  761. }
  762. if err := container.Unmount(); err != nil {
  763. log.Printf("%v: Failed to umount filesystem: %v", container.ID, err)
  764. }
  765. }
  766. func (container *Container) KillSig(sig int) error {
  767. container.Lock()
  768. defer container.Unlock()
  769. if !container.State.IsRunning() {
  770. return nil
  771. }
  772. return container.runtime.Kill(container, sig)
  773. }
  774. func (container *Container) Kill() error {
  775. if !container.State.IsRunning() {
  776. return nil
  777. }
  778. // 1. Send SIGKILL
  779. if err := container.KillSig(9); err != nil {
  780. return err
  781. }
  782. // 2. Wait for the process to die, in last resort, try to kill the process directly
  783. if err := container.WaitTimeout(10 * time.Second); err != nil {
  784. log.Printf("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL", utils.TruncateID(container.ID))
  785. if err := syscall.Kill(container.State.Pid, 9); err != nil {
  786. return err
  787. }
  788. }
  789. container.Wait()
  790. return nil
  791. }
  792. func (container *Container) Stop(seconds int) error {
  793. if !container.State.IsRunning() {
  794. return nil
  795. }
  796. // 1. Send a SIGTERM
  797. if err := container.KillSig(15); err != nil {
  798. utils.Debugf("Error sending kill SIGTERM: %s", err)
  799. log.Print("Failed to send SIGTERM to the process, force killing")
  800. if err := container.KillSig(9); err != nil {
  801. return err
  802. }
  803. }
  804. // 2. Wait for the process to exit on its own
  805. if err := container.WaitTimeout(time.Duration(seconds) * time.Second); err != nil {
  806. log.Printf("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.ID, seconds)
  807. // 3. If it doesn't, then send SIGKILL
  808. if err := container.Kill(); err != nil {
  809. return err
  810. }
  811. }
  812. return nil
  813. }
  814. func (container *Container) Restart(seconds int) error {
  815. // Avoid unnecessarily unmounting and then directly mounting
  816. // the container when the container stops and then starts
  817. // again
  818. if err := container.Mount(); err == nil {
  819. defer container.Unmount()
  820. }
  821. if err := container.Stop(seconds); err != nil {
  822. return err
  823. }
  824. return container.Start()
  825. }
  826. // Wait blocks until the container stops running, then returns its exit code.
  827. func (container *Container) Wait() int {
  828. <-container.waitLock
  829. return container.State.GetExitCode()
  830. }
  831. func (container *Container) Resize(h, w int) error {
  832. return container.command.Terminal.Resize(h, w)
  833. }
  834. func (container *Container) ExportRw() (archive.Archive, error) {
  835. if err := container.Mount(); err != nil {
  836. return nil, err
  837. }
  838. if container.runtime == nil {
  839. return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID)
  840. }
  841. archive, err := container.runtime.Diff(container)
  842. if err != nil {
  843. container.Unmount()
  844. return nil, err
  845. }
  846. return utils.NewReadCloserWrapper(archive, func() error {
  847. err := archive.Close()
  848. container.Unmount()
  849. return err
  850. }),
  851. nil
  852. }
  853. func (container *Container) Export() (archive.Archive, error) {
  854. if err := container.Mount(); err != nil {
  855. return nil, err
  856. }
  857. archive, err := archive.Tar(container.basefs, archive.Uncompressed)
  858. if err != nil {
  859. container.Unmount()
  860. return nil, err
  861. }
  862. return utils.NewReadCloserWrapper(archive, func() error {
  863. err := archive.Close()
  864. container.Unmount()
  865. return err
  866. }),
  867. nil
  868. }
  869. func (container *Container) WaitTimeout(timeout time.Duration) error {
  870. done := make(chan bool)
  871. go func() {
  872. container.Wait()
  873. done <- true
  874. }()
  875. select {
  876. case <-time.After(timeout):
  877. return fmt.Errorf("Timed Out")
  878. case <-done:
  879. return nil
  880. }
  881. }
  882. func (container *Container) Mount() error {
  883. return container.runtime.Mount(container)
  884. }
  885. func (container *Container) Changes() ([]archive.Change, error) {
  886. return container.runtime.Changes(container)
  887. }
  888. func (container *Container) GetImage() (*image.Image, error) {
  889. if container.runtime == nil {
  890. return nil, fmt.Errorf("Can't get image of unregistered container")
  891. }
  892. return container.runtime.graph.Get(container.Image)
  893. }
  894. func (container *Container) Unmount() error {
  895. return container.runtime.Unmount(container)
  896. }
  897. func (container *Container) logPath(name string) string {
  898. return path.Join(container.root, fmt.Sprintf("%s-%s.log", container.ID, name))
  899. }
  900. func (container *Container) ReadLog(name string) (io.Reader, error) {
  901. return os.Open(container.logPath(name))
  902. }
  903. func (container *Container) hostConfigPath() string {
  904. return path.Join(container.root, "hostconfig.json")
  905. }
  906. func (container *Container) jsonPath() string {
  907. return path.Join(container.root, "config.json")
  908. }
  909. func (container *Container) EnvConfigPath() (string, error) {
  910. p := path.Join(container.root, "config.env")
  911. if _, err := os.Stat(p); err != nil {
  912. if os.IsNotExist(err) {
  913. f, err := os.Create(p)
  914. if err != nil {
  915. return "", err
  916. }
  917. f.Close()
  918. } else {
  919. return "", err
  920. }
  921. }
  922. return p, nil
  923. }
  924. // This method must be exported to be used from the lxc template
  925. // This directory is only usable when the container is running
  926. func (container *Container) RootfsPath() string {
  927. return container.basefs
  928. }
  929. func validateID(id string) error {
  930. if id == "" {
  931. return fmt.Errorf("Invalid empty id")
  932. }
  933. return nil
  934. }
  935. // GetSize, return real size, virtual size
  936. func (container *Container) GetSize() (int64, int64) {
  937. var (
  938. sizeRw, sizeRootfs int64
  939. err error
  940. driver = container.runtime.driver
  941. )
  942. if err := container.Mount(); err != nil {
  943. utils.Errorf("Warning: failed to compute size of container rootfs %s: %s", container.ID, err)
  944. return sizeRw, sizeRootfs
  945. }
  946. defer container.Unmount()
  947. if differ, ok := container.runtime.driver.(graphdriver.Differ); ok {
  948. sizeRw, err = differ.DiffSize(container.ID)
  949. if err != nil {
  950. utils.Errorf("Warning: driver %s couldn't return diff size of container %s: %s", driver, container.ID, err)
  951. // FIXME: GetSize should return an error. Not changing it now in case
  952. // there is a side-effect.
  953. sizeRw = -1
  954. }
  955. } else {
  956. changes, _ := container.Changes()
  957. if changes != nil {
  958. sizeRw = archive.ChangesSize(container.basefs, changes)
  959. } else {
  960. sizeRw = -1
  961. }
  962. }
  963. if _, err = os.Stat(container.basefs); err != nil {
  964. if sizeRootfs, err = utils.TreeSize(container.basefs); err != nil {
  965. sizeRootfs = -1
  966. }
  967. }
  968. return sizeRw, sizeRootfs
  969. }
  970. func (container *Container) Copy(resource string) (io.ReadCloser, error) {
  971. if err := container.Mount(); err != nil {
  972. return nil, err
  973. }
  974. var filter []string
  975. basePath := path.Join(container.basefs, resource)
  976. stat, err := os.Stat(basePath)
  977. if err != nil {
  978. container.Unmount()
  979. return nil, err
  980. }
  981. if !stat.IsDir() {
  982. d, f := path.Split(basePath)
  983. basePath = d
  984. filter = []string{f}
  985. } else {
  986. filter = []string{path.Base(basePath)}
  987. basePath = path.Dir(basePath)
  988. }
  989. archive, err := archive.TarFilter(basePath, &archive.TarOptions{
  990. Compression: archive.Uncompressed,
  991. Includes: filter,
  992. })
  993. if err != nil {
  994. return nil, err
  995. }
  996. return utils.NewReadCloserWrapper(archive, func() error {
  997. err := archive.Close()
  998. container.Unmount()
  999. return err
  1000. }),
  1001. nil
  1002. }
  1003. // Returns true if the container exposes a certain port
  1004. func (container *Container) Exposes(p nat.Port) bool {
  1005. _, exists := container.Config.ExposedPorts[p]
  1006. return exists
  1007. }
  1008. func (container *Container) GetPtyMaster() (*os.File, error) {
  1009. ttyConsole, ok := container.command.Terminal.(execdriver.TtyTerminal)
  1010. if !ok {
  1011. return nil, ErrNoTTY
  1012. }
  1013. return ttyConsole.Master(), nil
  1014. }
  1015. func (container *Container) HostConfig() *runconfig.HostConfig {
  1016. return container.hostConfig
  1017. }
  1018. func (container *Container) SetHostConfig(hostConfig *runconfig.HostConfig) {
  1019. container.hostConfig = hostConfig
  1020. }
  1021. func (container *Container) DisableLink(name string) {
  1022. if container.activeLinks != nil {
  1023. if link, exists := container.activeLinks[name]; exists {
  1024. link.Disable()
  1025. } else {
  1026. utils.Debugf("Could not find active link for %s", name)
  1027. }
  1028. }
  1029. }