container.go 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477
  1. package docker
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "github.com/dotcloud/docker/archive"
  8. "github.com/dotcloud/docker/graphdriver"
  9. "github.com/dotcloud/docker/term"
  10. "github.com/dotcloud/docker/utils"
  11. "github.com/kr/pty"
  12. "io"
  13. "io/ioutil"
  14. "log"
  15. "net"
  16. "os"
  17. "os/exec"
  18. "path"
  19. "strconv"
  20. "strings"
  21. "sync"
  22. "syscall"
  23. "time"
  24. )
  25. var (
  26. ErrNotATTY = errors.New("The PTY is not a file")
  27. ErrNoTTY = errors.New("No PTY found")
  28. )
  29. type Container struct {
  30. sync.Mutex
  31. root string // Path to the "home" of the container, including metadata.
  32. rootfs string // Path to the root filesystem of the container.
  33. ID string
  34. Created time.Time
  35. Path string
  36. Args []string
  37. Config *Config
  38. State State
  39. Image string
  40. network *NetworkInterface
  41. NetworkSettings *NetworkSettings
  42. SysInitPath string
  43. ResolvConfPath string
  44. HostnamePath string
  45. HostsPath string
  46. Name string
  47. Driver string
  48. cmd *exec.Cmd
  49. stdout *utils.WriteBroadcaster
  50. stderr *utils.WriteBroadcaster
  51. stdin io.ReadCloser
  52. stdinPipe io.WriteCloser
  53. ptyMaster io.Closer
  54. runtime *Runtime
  55. waitLock chan struct{}
  56. Volumes map[string]string
  57. // Store rw/ro in a separate structure to preserve reverse-compatibility on-disk.
  58. // Easier than migrating older container configs :)
  59. VolumesRW map[string]bool
  60. hostConfig *HostConfig
  61. activeLinks map[string]*Link
  62. }
  63. // Note: the Config structure should hold only portable information about the container.
  64. // Here, "portable" means "independent from the host we are running on".
  65. // Non-portable information *should* appear in HostConfig.
  66. type Config struct {
  67. Hostname string
  68. Domainname string
  69. User string
  70. Memory int64 // Memory limit (in bytes)
  71. MemorySwap int64 // Total memory usage (memory + swap); set `-1' to disable swap
  72. CpuShares int64 // CPU shares (relative weight vs. other containers)
  73. AttachStdin bool
  74. AttachStdout bool
  75. AttachStderr bool
  76. PortSpecs []string // Deprecated - Can be in the format of 8080/tcp
  77. ExposedPorts map[Port]struct{}
  78. Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
  79. OpenStdin bool // Open stdin
  80. StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
  81. Env []string
  82. Cmd []string
  83. Dns []string
  84. Image string // Name of the image as it was passed by the operator (eg. could be symbolic)
  85. Volumes map[string]struct{}
  86. VolumesFrom string
  87. WorkingDir string
  88. Entrypoint []string
  89. NetworkDisabled bool
  90. }
  91. type HostConfig struct {
  92. Binds []string
  93. ContainerIDFile string
  94. LxcConf []KeyValuePair
  95. Privileged bool
  96. PortBindings map[Port][]PortBinding
  97. Links []string
  98. PublishAllPorts bool
  99. }
  100. type BindMap struct {
  101. SrcPath string
  102. DstPath string
  103. Mode string
  104. }
  105. var (
  106. ErrContainerStart = errors.New("The container failed to start. Unkown error")
  107. ErrContainerStartTimeout = errors.New("The container failed to start due to timed out.")
  108. ErrInvalidWorikingDirectory = errors.New("The working directory is invalid. It needs to be an absolute path.")
  109. ErrConflictAttachDetach = errors.New("Conflicting options: -a and -d")
  110. ErrConflictDetachAutoRemove = errors.New("Conflicting options: -rm and -d")
  111. )
  112. type KeyValuePair struct {
  113. Key string
  114. Value string
  115. }
  116. type PortBinding struct {
  117. HostIp string
  118. HostPort string
  119. }
  120. // 80/tcp
  121. type Port string
  122. func (p Port) Proto() string {
  123. parts := strings.Split(string(p), "/")
  124. if len(parts) == 1 {
  125. return "tcp"
  126. }
  127. return parts[1]
  128. }
  129. func (p Port) Port() string {
  130. return strings.Split(string(p), "/")[0]
  131. }
  132. func (p Port) Int() int {
  133. i, err := parsePort(p.Port())
  134. if err != nil {
  135. panic(err)
  136. }
  137. return i
  138. }
  139. func NewPort(proto, port string) Port {
  140. return Port(fmt.Sprintf("%s/%s", port, proto))
  141. }
  142. type PortMapping map[string]string // Deprecated
  143. type NetworkSettings struct {
  144. IPAddress string
  145. IPPrefixLen int
  146. Gateway string
  147. Bridge string
  148. PortMapping map[string]PortMapping // Deprecated
  149. Ports map[Port][]PortBinding
  150. }
  151. func (settings *NetworkSettings) PortMappingAPI() []APIPort {
  152. var mapping []APIPort
  153. for port, bindings := range settings.Ports {
  154. p, _ := parsePort(port.Port())
  155. if len(bindings) == 0 {
  156. mapping = append(mapping, APIPort{
  157. PublicPort: int64(p),
  158. Type: port.Proto(),
  159. })
  160. continue
  161. }
  162. for _, binding := range bindings {
  163. p, _ := parsePort(port.Port())
  164. h, _ := parsePort(binding.HostPort)
  165. mapping = append(mapping, APIPort{
  166. PrivatePort: int64(p),
  167. PublicPort: int64(h),
  168. Type: port.Proto(),
  169. IP: binding.HostIp,
  170. })
  171. }
  172. }
  173. return mapping
  174. }
  175. // Inject the io.Reader at the given path. Note: do not close the reader
  176. func (container *Container) Inject(file io.Reader, pth string) error {
  177. if err := container.EnsureMounted(); err != nil {
  178. return fmt.Errorf("inject: error mounting container %s: %s", container.ID, err)
  179. }
  180. // Return error if path exists
  181. destPath := path.Join(container.RootfsPath(), pth)
  182. if _, err := os.Stat(destPath); err == nil {
  183. // Since err is nil, the path could be stat'd and it exists
  184. return fmt.Errorf("%s exists", pth)
  185. } else if !os.IsNotExist(err) {
  186. // Expect err might be that the file doesn't exist, so
  187. // if it's some other error, return that.
  188. return err
  189. }
  190. // Make sure the directory exists
  191. if err := os.MkdirAll(path.Join(container.RootfsPath(), path.Dir(pth)), 0755); err != nil {
  192. return err
  193. }
  194. dest, err := os.Create(destPath)
  195. if err != nil {
  196. return err
  197. }
  198. defer dest.Close()
  199. if _, err := io.Copy(dest, file); err != nil {
  200. return err
  201. }
  202. return nil
  203. }
  204. func (container *Container) Cmd() *exec.Cmd {
  205. return container.cmd
  206. }
  207. func (container *Container) When() time.Time {
  208. return container.Created
  209. }
  210. func (container *Container) FromDisk() error {
  211. data, err := ioutil.ReadFile(container.jsonPath())
  212. if err != nil {
  213. return err
  214. }
  215. // Load container settings
  216. // udp broke compat of docker.PortMapping, but it's not used when loading a container, we can skip it
  217. if err := json.Unmarshal(data, container); err != nil && !strings.Contains(err.Error(), "docker.PortMapping") {
  218. return err
  219. }
  220. return container.readHostConfig()
  221. }
  222. func (container *Container) ToDisk() (err error) {
  223. data, err := json.Marshal(container)
  224. if err != nil {
  225. return
  226. }
  227. err = ioutil.WriteFile(container.jsonPath(), data, 0666)
  228. if err != nil {
  229. return
  230. }
  231. return container.writeHostConfig()
  232. }
  233. func (container *Container) readHostConfig() error {
  234. container.hostConfig = &HostConfig{}
  235. // If the hostconfig file does not exist, do not read it.
  236. // (We still have to initialize container.hostConfig,
  237. // but that's OK, since we just did that above.)
  238. _, err := os.Stat(container.hostConfigPath())
  239. if os.IsNotExist(err) {
  240. return nil
  241. }
  242. data, err := ioutil.ReadFile(container.hostConfigPath())
  243. if err != nil {
  244. return err
  245. }
  246. return json.Unmarshal(data, container.hostConfig)
  247. }
  248. func (container *Container) writeHostConfig() (err error) {
  249. data, err := json.Marshal(container.hostConfig)
  250. if err != nil {
  251. return
  252. }
  253. return ioutil.WriteFile(container.hostConfigPath(), data, 0666)
  254. }
  255. func (container *Container) generateEnvConfig(env []string) error {
  256. data, err := json.Marshal(env)
  257. if err != nil {
  258. return err
  259. }
  260. ioutil.WriteFile(container.EnvConfigPath(), data, 0600)
  261. return nil
  262. }
  263. func (container *Container) generateLXCConfig() error {
  264. fo, err := os.Create(container.lxcConfigPath())
  265. if err != nil {
  266. return err
  267. }
  268. defer fo.Close()
  269. return LxcTemplateCompiled.Execute(fo, container)
  270. }
  271. func (container *Container) startPty() error {
  272. ptyMaster, ptySlave, err := pty.Open()
  273. if err != nil {
  274. return err
  275. }
  276. container.ptyMaster = ptyMaster
  277. container.cmd.Stdout = ptySlave
  278. container.cmd.Stderr = ptySlave
  279. // Copy the PTYs to our broadcasters
  280. go func() {
  281. defer container.stdout.CloseWriters()
  282. utils.Debugf("startPty: begin of stdout pipe")
  283. io.Copy(container.stdout, ptyMaster)
  284. utils.Debugf("startPty: end of stdout pipe")
  285. }()
  286. // stdin
  287. if container.Config.OpenStdin {
  288. container.cmd.Stdin = ptySlave
  289. container.cmd.SysProcAttr.Setctty = true
  290. go func() {
  291. defer container.stdin.Close()
  292. utils.Debugf("startPty: begin of stdin pipe")
  293. io.Copy(ptyMaster, container.stdin)
  294. utils.Debugf("startPty: end of stdin pipe")
  295. }()
  296. }
  297. if err := container.cmd.Start(); err != nil {
  298. return err
  299. }
  300. ptySlave.Close()
  301. return nil
  302. }
  303. func (container *Container) start() error {
  304. container.cmd.Stdout = container.stdout
  305. container.cmd.Stderr = container.stderr
  306. if container.Config.OpenStdin {
  307. stdin, err := container.cmd.StdinPipe()
  308. if err != nil {
  309. return err
  310. }
  311. go func() {
  312. defer stdin.Close()
  313. utils.Debugf("start: begin of stdin pipe")
  314. io.Copy(stdin, container.stdin)
  315. utils.Debugf("start: end of stdin pipe")
  316. }()
  317. }
  318. return container.cmd.Start()
  319. }
  320. func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, stdout io.Writer, stderr io.Writer) chan error {
  321. var cStdout, cStderr io.ReadCloser
  322. var nJobs int
  323. errors := make(chan error, 3)
  324. if stdin != nil && container.Config.OpenStdin {
  325. nJobs += 1
  326. if cStdin, err := container.StdinPipe(); err != nil {
  327. errors <- err
  328. } else {
  329. go func() {
  330. utils.Debugf("attach: stdin: begin")
  331. defer utils.Debugf("attach: stdin: end")
  332. // No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
  333. if container.Config.StdinOnce && !container.Config.Tty {
  334. defer cStdin.Close()
  335. } else {
  336. if cStdout != nil {
  337. defer cStdout.Close()
  338. }
  339. if cStderr != nil {
  340. defer cStderr.Close()
  341. }
  342. }
  343. if container.Config.Tty {
  344. _, err = utils.CopyEscapable(cStdin, stdin)
  345. } else {
  346. _, err = io.Copy(cStdin, stdin)
  347. }
  348. if err == io.ErrClosedPipe {
  349. err = nil
  350. }
  351. if err != nil {
  352. utils.Errorf("attach: stdin: %s", err)
  353. }
  354. errors <- err
  355. }()
  356. }
  357. }
  358. if stdout != nil {
  359. nJobs += 1
  360. if p, err := container.StdoutPipe(); err != nil {
  361. errors <- err
  362. } else {
  363. cStdout = p
  364. go func() {
  365. utils.Debugf("attach: stdout: begin")
  366. defer utils.Debugf("attach: stdout: end")
  367. // If we are in StdinOnce mode, then close stdin
  368. if container.Config.StdinOnce && stdin != nil {
  369. defer stdin.Close()
  370. }
  371. if stdinCloser != nil {
  372. defer stdinCloser.Close()
  373. }
  374. _, err := io.Copy(stdout, cStdout)
  375. if err == io.ErrClosedPipe {
  376. err = nil
  377. }
  378. if err != nil {
  379. utils.Errorf("attach: stdout: %s", err)
  380. }
  381. errors <- err
  382. }()
  383. }
  384. } else {
  385. go func() {
  386. if stdinCloser != nil {
  387. defer stdinCloser.Close()
  388. }
  389. if cStdout, err := container.StdoutPipe(); err != nil {
  390. utils.Errorf("attach: stdout pipe: %s", err)
  391. } else {
  392. io.Copy(&utils.NopWriter{}, cStdout)
  393. }
  394. }()
  395. }
  396. if stderr != nil {
  397. nJobs += 1
  398. if p, err := container.StderrPipe(); err != nil {
  399. errors <- err
  400. } else {
  401. cStderr = p
  402. go func() {
  403. utils.Debugf("attach: stderr: begin")
  404. defer utils.Debugf("attach: stderr: end")
  405. // If we are in StdinOnce mode, then close stdin
  406. if container.Config.StdinOnce && stdin != nil {
  407. defer stdin.Close()
  408. }
  409. if stdinCloser != nil {
  410. defer stdinCloser.Close()
  411. }
  412. _, err := io.Copy(stderr, cStderr)
  413. if err == io.ErrClosedPipe {
  414. err = nil
  415. }
  416. if err != nil {
  417. utils.Errorf("attach: stderr: %s", err)
  418. }
  419. errors <- err
  420. }()
  421. }
  422. } else {
  423. go func() {
  424. if stdinCloser != nil {
  425. defer stdinCloser.Close()
  426. }
  427. if cStderr, err := container.StderrPipe(); err != nil {
  428. utils.Errorf("attach: stdout pipe: %s", err)
  429. } else {
  430. io.Copy(&utils.NopWriter{}, cStderr)
  431. }
  432. }()
  433. }
  434. return utils.Go(func() error {
  435. if cStdout != nil {
  436. defer cStdout.Close()
  437. }
  438. if cStderr != nil {
  439. defer cStderr.Close()
  440. }
  441. // FIXME: how to clean up the stdin goroutine without the unwanted side effect
  442. // of closing the passed stdin? Add an intermediary io.Pipe?
  443. for i := 0; i < nJobs; i += 1 {
  444. utils.Debugf("attach: waiting for job %d/%d", i+1, nJobs)
  445. if err := <-errors; err != nil {
  446. utils.Errorf("attach: job %d returned error %s, aborting all jobs", i+1, err)
  447. return err
  448. }
  449. utils.Debugf("attach: job %d completed successfully", i+1)
  450. }
  451. utils.Debugf("attach: all jobs completed successfully")
  452. return nil
  453. })
  454. }
  455. func (container *Container) Start() (err error) {
  456. container.Lock()
  457. defer container.Unlock()
  458. if container.State.IsRunning() {
  459. return fmt.Errorf("The container %s is already running.", container.ID)
  460. }
  461. defer func() {
  462. if err != nil {
  463. container.cleanup()
  464. }
  465. }()
  466. if err := container.EnsureMounted(); err != nil {
  467. return err
  468. }
  469. if container.runtime.networkManager.disabled {
  470. container.Config.NetworkDisabled = true
  471. container.buildHostnameAndHostsFiles("127.0.1.1")
  472. } else {
  473. if err := container.allocateNetwork(); err != nil {
  474. return err
  475. }
  476. container.buildHostnameAndHostsFiles(container.NetworkSettings.IPAddress)
  477. }
  478. // Make sure the config is compatible with the current kernel
  479. if container.Config.Memory > 0 && !container.runtime.capabilities.MemoryLimit {
  480. log.Printf("WARNING: Your kernel does not support memory limit capabilities. Limitation discarded.\n")
  481. container.Config.Memory = 0
  482. }
  483. if container.Config.Memory > 0 && !container.runtime.capabilities.SwapLimit {
  484. log.Printf("WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
  485. container.Config.MemorySwap = -1
  486. }
  487. if container.runtime.capabilities.IPv4ForwardingDisabled {
  488. log.Printf("WARNING: IPv4 forwarding is disabled. Networking will not work")
  489. }
  490. if container.Volumes == nil || len(container.Volumes) == 0 {
  491. container.Volumes = make(map[string]string)
  492. container.VolumesRW = make(map[string]bool)
  493. }
  494. // Apply volumes from another container if requested
  495. if err := container.applyExternalVolumes(); err != nil {
  496. return err
  497. }
  498. if err := container.createVolumes(); err != nil {
  499. return err
  500. }
  501. if err := container.generateLXCConfig(); err != nil {
  502. return err
  503. }
  504. var lxcStart string = "lxc-start"
  505. if container.hostConfig.Privileged && container.runtime.capabilities.AppArmor {
  506. lxcStart = path.Join(container.runtime.config.Root, "lxc-start-unconfined")
  507. }
  508. params := []string{
  509. lxcStart,
  510. "-n", container.ID,
  511. "-f", container.lxcConfigPath(),
  512. "--",
  513. "/.dockerinit",
  514. }
  515. // Networking
  516. if !container.Config.NetworkDisabled {
  517. network := container.NetworkSettings
  518. params = append(params,
  519. "-g", network.Gateway,
  520. "-i", fmt.Sprintf("%s/%d", network.IPAddress, network.IPPrefixLen),
  521. )
  522. }
  523. // User
  524. if container.Config.User != "" {
  525. params = append(params, "-u", container.Config.User)
  526. }
  527. // Setup environment
  528. env := []string{
  529. "HOME=/",
  530. "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
  531. "HOSTNAME=" + container.Config.Hostname,
  532. }
  533. if container.Config.Tty {
  534. env = append(env, "TERM=xterm")
  535. }
  536. if container.hostConfig.Privileged {
  537. params = append(params, "-privileged")
  538. }
  539. // Init any links between the parent and children
  540. runtime := container.runtime
  541. children, err := runtime.Children(container.Name)
  542. if err != nil {
  543. return err
  544. }
  545. if len(children) > 0 {
  546. container.activeLinks = make(map[string]*Link, len(children))
  547. // If we encounter an error make sure that we rollback any network
  548. // config and ip table changes
  549. rollback := func() {
  550. for _, link := range container.activeLinks {
  551. link.Disable()
  552. }
  553. container.activeLinks = nil
  554. }
  555. for p, child := range children {
  556. link, err := NewLink(container, child, p, runtime.networkManager.bridgeIface)
  557. if err != nil {
  558. rollback()
  559. return err
  560. }
  561. container.activeLinks[link.Alias()] = link
  562. if err := link.Enable(); err != nil {
  563. rollback()
  564. return err
  565. }
  566. for _, envVar := range link.ToEnv() {
  567. env = append(env, envVar)
  568. }
  569. }
  570. }
  571. for _, elem := range container.Config.Env {
  572. env = append(env, elem)
  573. }
  574. if err := container.generateEnvConfig(env); err != nil {
  575. return err
  576. }
  577. if container.Config.WorkingDir != "" {
  578. workingDir := path.Clean(container.Config.WorkingDir)
  579. utils.Debugf("[working dir] working dir is %s", workingDir)
  580. if err := os.MkdirAll(path.Join(container.RootfsPath(), workingDir), 0755); err != nil {
  581. return nil
  582. }
  583. params = append(params,
  584. "-w", workingDir,
  585. )
  586. }
  587. // Program
  588. params = append(params, "--", container.Path)
  589. params = append(params, container.Args...)
  590. if RootIsShared() {
  591. // lxc-start really needs / to be non-shared, or all kinds of stuff break
  592. // when lxc-start unmount things and those unmounts propagate to the main
  593. // mount namespace.
  594. // What we really want is to clone into a new namespace and then
  595. // mount / MS_REC|MS_SLAVE, but since we can't really clone or fork
  596. // without exec in go we have to do this horrible shell hack...
  597. shellString :=
  598. "mount --make-rslave /; exec " +
  599. utils.ShellQuoteArguments(params)
  600. params = []string{
  601. "unshare", "-m", "--", "/bin/sh", "-c", shellString,
  602. }
  603. }
  604. container.cmd = exec.Command(params[0], params[1:]...)
  605. // Setup logging of stdout and stderr to disk
  606. if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
  607. return err
  608. }
  609. if err := container.runtime.LogToDisk(container.stderr, container.logPath("json"), "stderr"); err != nil {
  610. return err
  611. }
  612. container.cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
  613. if container.Config.Tty {
  614. err = container.startPty()
  615. } else {
  616. err = container.start()
  617. }
  618. if err != nil {
  619. return err
  620. }
  621. // FIXME: save state on disk *first*, then converge
  622. // this way disk state is used as a journal, eg. we can restore after crash etc.
  623. container.State.SetRunning(container.cmd.Process.Pid)
  624. // Init the lock
  625. container.waitLock = make(chan struct{})
  626. container.ToDisk()
  627. go container.monitor()
  628. defer utils.Debugf("Container running: %v", container.State.IsRunning())
  629. // We wait for the container to be fully running.
  630. // Timeout after 5 seconds. In case of broken pipe, just retry.
  631. // Note: The container can run and finish correctly before
  632. // the end of this loop
  633. for now := time.Now(); time.Since(now) < 5*time.Second; {
  634. // If the container dies while waiting for it, just return
  635. if !container.State.IsRunning() {
  636. return nil
  637. }
  638. output, err := exec.Command("lxc-info", "-s", "-n", container.ID).CombinedOutput()
  639. if err != nil {
  640. utils.Debugf("Error with lxc-info: %s (%s)", err, output)
  641. output, err = exec.Command("lxc-info", "-s", "-n", container.ID).CombinedOutput()
  642. if err != nil {
  643. utils.Debugf("Second Error with lxc-info: %s (%s)", err, output)
  644. return err
  645. }
  646. }
  647. if strings.Contains(string(output), "RUNNING") {
  648. return nil
  649. }
  650. utils.Debugf("Waiting for the container to start (running: %v): %s", container.State.IsRunning(), bytes.TrimSpace(output))
  651. time.Sleep(50 * time.Millisecond)
  652. }
  653. if container.State.IsRunning() {
  654. return ErrContainerStartTimeout
  655. }
  656. return ErrContainerStart
  657. }
  658. func (container *Container) getBindMap() (map[string]BindMap, error) {
  659. // Create the requested bind mounts
  660. binds := make(map[string]BindMap)
  661. // Define illegal container destinations
  662. illegalDsts := []string{"/", "."}
  663. for _, bind := range container.hostConfig.Binds {
  664. // FIXME: factorize bind parsing in parseBind
  665. var src, dst, mode string
  666. arr := strings.Split(bind, ":")
  667. if len(arr) == 2 {
  668. src = arr[0]
  669. dst = arr[1]
  670. mode = "rw"
  671. } else if len(arr) == 3 {
  672. src = arr[0]
  673. dst = arr[1]
  674. mode = arr[2]
  675. } else {
  676. return nil, fmt.Errorf("Invalid bind specification: %s", bind)
  677. }
  678. // Bail if trying to mount to an illegal destination
  679. for _, illegal := range illegalDsts {
  680. if dst == illegal {
  681. return nil, fmt.Errorf("Illegal bind destination: %s", dst)
  682. }
  683. }
  684. bindMap := BindMap{
  685. SrcPath: src,
  686. DstPath: dst,
  687. Mode: mode,
  688. }
  689. binds[path.Clean(dst)] = bindMap
  690. }
  691. return binds, nil
  692. }
  693. func (container *Container) createVolumes() error {
  694. binds, err := container.getBindMap()
  695. if err != nil {
  696. return err
  697. }
  698. volumesDriver := container.runtime.volumes.driver
  699. // Create the requested volumes if they don't exist
  700. for volPath := range container.Config.Volumes {
  701. volPath = path.Clean(volPath)
  702. volIsDir := true
  703. // Skip existing volumes
  704. if _, exists := container.Volumes[volPath]; exists {
  705. continue
  706. }
  707. var srcPath string
  708. var isBindMount bool
  709. srcRW := false
  710. // If an external bind is defined for this volume, use that as a source
  711. if bindMap, exists := binds[volPath]; exists {
  712. isBindMount = true
  713. srcPath = bindMap.SrcPath
  714. if strings.ToLower(bindMap.Mode) == "rw" {
  715. srcRW = true
  716. }
  717. if stat, err := os.Lstat(bindMap.SrcPath); err != nil {
  718. return err
  719. } else {
  720. volIsDir = stat.IsDir()
  721. }
  722. // Otherwise create an directory in $ROOT/volumes/ and use that
  723. } else {
  724. // Do not pass a container as the parameter for the volume creation.
  725. // The graph driver using the container's information ( Image ) to
  726. // create the parent.
  727. c, err := container.runtime.volumes.Create(nil, nil, "", "", nil)
  728. if err != nil {
  729. return err
  730. }
  731. srcPath, err = volumesDriver.Get(c.ID)
  732. if err != nil {
  733. return fmt.Errorf("Driver %s failed to get volume rootfs %s: %s", volumesDriver, c.ID, err)
  734. }
  735. srcRW = true // RW by default
  736. }
  737. container.Volumes[volPath] = srcPath
  738. container.VolumesRW[volPath] = srcRW
  739. // Create the mountpoint
  740. volPath = path.Join(container.RootfsPath(), volPath)
  741. rootVolPath, err := utils.FollowSymlinkInScope(volPath, container.RootfsPath())
  742. if err != nil {
  743. return err
  744. }
  745. if _, err := os.Stat(rootVolPath); err != nil {
  746. if os.IsNotExist(err) {
  747. if volIsDir {
  748. if err := os.MkdirAll(rootVolPath, 0755); err != nil {
  749. return err
  750. }
  751. } else {
  752. if err := os.MkdirAll(path.Dir(rootVolPath), 0755); err != nil {
  753. return err
  754. }
  755. if f, err := os.OpenFile(rootVolPath, os.O_CREATE, 0755); err != nil {
  756. return err
  757. } else {
  758. f.Close()
  759. }
  760. }
  761. }
  762. }
  763. // Do not copy or change permissions if we are mounting from the host
  764. if srcRW && !isBindMount {
  765. volList, err := ioutil.ReadDir(rootVolPath)
  766. if err != nil {
  767. return err
  768. }
  769. if len(volList) > 0 {
  770. srcList, err := ioutil.ReadDir(srcPath)
  771. if err != nil {
  772. return err
  773. }
  774. if len(srcList) == 0 {
  775. // If the source volume is empty copy files from the root into the volume
  776. if err := archive.CopyWithTar(rootVolPath, srcPath); err != nil {
  777. return err
  778. }
  779. var stat syscall.Stat_t
  780. if err := syscall.Stat(rootVolPath, &stat); err != nil {
  781. return err
  782. }
  783. var srcStat syscall.Stat_t
  784. if err := syscall.Stat(srcPath, &srcStat); err != nil {
  785. return err
  786. }
  787. // Change the source volume's ownership if it differs from the root
  788. // files that where just copied
  789. if stat.Uid != srcStat.Uid || stat.Gid != srcStat.Gid {
  790. if err := os.Chown(srcPath, int(stat.Uid), int(stat.Gid)); err != nil {
  791. return err
  792. }
  793. }
  794. }
  795. }
  796. }
  797. }
  798. return nil
  799. }
  800. func (container *Container) applyExternalVolumes() error {
  801. if container.Config.VolumesFrom != "" {
  802. containerSpecs := strings.Split(container.Config.VolumesFrom, ",")
  803. for _, containerSpec := range containerSpecs {
  804. mountRW := true
  805. specParts := strings.SplitN(containerSpec, ":", 2)
  806. switch len(specParts) {
  807. case 0:
  808. return fmt.Errorf("Malformed volumes-from specification: %s", container.Config.VolumesFrom)
  809. case 2:
  810. switch specParts[1] {
  811. case "ro":
  812. mountRW = false
  813. case "rw": // mountRW is already true
  814. default:
  815. return fmt.Errorf("Malformed volumes-from speficication: %s", containerSpec)
  816. }
  817. }
  818. c := container.runtime.Get(specParts[0])
  819. if c == nil {
  820. return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.ID)
  821. }
  822. for volPath, id := range c.Volumes {
  823. if _, exists := container.Volumes[volPath]; exists {
  824. continue
  825. }
  826. if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
  827. return err
  828. }
  829. container.Volumes[volPath] = id
  830. if isRW, exists := c.VolumesRW[volPath]; exists {
  831. container.VolumesRW[volPath] = isRW && mountRW
  832. }
  833. }
  834. }
  835. }
  836. return nil
  837. }
  838. func (container *Container) Run() error {
  839. if err := container.Start(); err != nil {
  840. return err
  841. }
  842. container.Wait()
  843. return nil
  844. }
  845. func (container *Container) Output() (output []byte, err error) {
  846. pipe, err := container.StdoutPipe()
  847. if err != nil {
  848. return nil, err
  849. }
  850. defer pipe.Close()
  851. if err := container.Start(); err != nil {
  852. return nil, err
  853. }
  854. output, err = ioutil.ReadAll(pipe)
  855. container.Wait()
  856. return output, err
  857. }
  858. // Container.StdinPipe returns a WriteCloser which can be used to feed data
  859. // to the standard input of the container's active process.
  860. // Container.StdoutPipe and Container.StderrPipe each return a ReadCloser
  861. // which can be used to retrieve the standard output (and error) generated
  862. // by the container's active process. The output (and error) are actually
  863. // copied and delivered to all StdoutPipe and StderrPipe consumers, using
  864. // a kind of "broadcaster".
  865. func (container *Container) StdinPipe() (io.WriteCloser, error) {
  866. return container.stdinPipe, nil
  867. }
  868. func (container *Container) StdoutPipe() (io.ReadCloser, error) {
  869. reader, writer := io.Pipe()
  870. container.stdout.AddWriter(writer, "")
  871. return utils.NewBufReader(reader), nil
  872. }
  873. func (container *Container) StderrPipe() (io.ReadCloser, error) {
  874. reader, writer := io.Pipe()
  875. container.stderr.AddWriter(writer, "")
  876. return utils.NewBufReader(reader), nil
  877. }
  878. func (container *Container) buildHostnameAndHostsFiles(IP string) {
  879. container.HostnamePath = path.Join(container.root, "hostname")
  880. ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
  881. hostsContent := []byte(`
  882. 127.0.0.1 localhost
  883. ::1 localhost ip6-localhost ip6-loopback
  884. fe00::0 ip6-localnet
  885. ff00::0 ip6-mcastprefix
  886. ff02::1 ip6-allnodes
  887. ff02::2 ip6-allrouters
  888. `)
  889. container.HostsPath = path.Join(container.root, "hosts")
  890. if container.Config.Domainname != "" {
  891. hostsContent = append([]byte(fmt.Sprintf("%s\t%s.%s %s\n", IP, container.Config.Hostname, container.Config.Domainname, container.Config.Hostname)), hostsContent...)
  892. } else {
  893. hostsContent = append([]byte(fmt.Sprintf("%s\t%s\n", IP, container.Config.Hostname)), hostsContent...)
  894. }
  895. ioutil.WriteFile(container.HostsPath, hostsContent, 0644)
  896. }
  897. func (container *Container) allocateNetwork() error {
  898. if container.Config.NetworkDisabled {
  899. return nil
  900. }
  901. var (
  902. iface *NetworkInterface
  903. err error
  904. )
  905. if container.State.IsGhost() {
  906. if manager := container.runtime.networkManager; manager.disabled {
  907. iface = &NetworkInterface{disabled: true}
  908. } else {
  909. iface = &NetworkInterface{
  910. IPNet: net.IPNet{IP: net.ParseIP(container.NetworkSettings.IPAddress), Mask: manager.bridgeNetwork.Mask},
  911. Gateway: manager.bridgeNetwork.IP,
  912. manager: manager,
  913. }
  914. if iface != nil && iface.IPNet.IP != nil {
  915. ipNum := ipToInt(iface.IPNet.IP)
  916. manager.ipAllocator.inUse[ipNum] = struct{}{}
  917. } else {
  918. iface, err = container.runtime.networkManager.Allocate()
  919. if err != nil {
  920. return err
  921. }
  922. }
  923. }
  924. } else {
  925. iface, err = container.runtime.networkManager.Allocate()
  926. if err != nil {
  927. return err
  928. }
  929. }
  930. if container.Config.PortSpecs != nil {
  931. utils.Debugf("Migrating port mappings for container: %s", strings.Join(container.Config.PortSpecs, ", "))
  932. if err := migratePortMappings(container.Config, container.hostConfig); err != nil {
  933. return err
  934. }
  935. container.Config.PortSpecs = nil
  936. if err := container.writeHostConfig(); err != nil {
  937. return err
  938. }
  939. }
  940. var (
  941. portSpecs = make(map[Port]struct{})
  942. bindings = make(map[Port][]PortBinding)
  943. )
  944. if !container.State.IsGhost() {
  945. if container.Config.ExposedPorts != nil {
  946. portSpecs = container.Config.ExposedPorts
  947. }
  948. if container.hostConfig.PortBindings != nil {
  949. bindings = container.hostConfig.PortBindings
  950. }
  951. } else {
  952. if container.NetworkSettings.Ports != nil {
  953. for port, binding := range container.NetworkSettings.Ports {
  954. portSpecs[port] = struct{}{}
  955. bindings[port] = binding
  956. }
  957. }
  958. }
  959. container.NetworkSettings.PortMapping = nil
  960. for port := range portSpecs {
  961. binding := bindings[port]
  962. if container.hostConfig.PublishAllPorts && len(binding) == 0 {
  963. binding = append(binding, PortBinding{})
  964. }
  965. for i := 0; i < len(binding); i++ {
  966. b := binding[i]
  967. nat, err := iface.AllocatePort(port, b)
  968. if err != nil {
  969. iface.Release()
  970. return err
  971. }
  972. utils.Debugf("Allocate port: %s:%s->%s", nat.Binding.HostIp, port, nat.Binding.HostPort)
  973. binding[i] = nat.Binding
  974. }
  975. bindings[port] = binding
  976. }
  977. container.writeHostConfig()
  978. container.NetworkSettings.Ports = bindings
  979. container.network = iface
  980. container.NetworkSettings.Bridge = container.runtime.networkManager.bridgeIface
  981. container.NetworkSettings.IPAddress = iface.IPNet.IP.String()
  982. container.NetworkSettings.IPPrefixLen, _ = iface.IPNet.Mask.Size()
  983. container.NetworkSettings.Gateway = iface.Gateway.String()
  984. return nil
  985. }
  986. func (container *Container) releaseNetwork() {
  987. if container.Config.NetworkDisabled || container.network == nil {
  988. return
  989. }
  990. container.network.Release()
  991. container.network = nil
  992. container.NetworkSettings = &NetworkSettings{}
  993. }
  994. // FIXME: replace this with a control socket within dockerinit
  995. func (container *Container) waitLxc() error {
  996. for {
  997. output, err := exec.Command("lxc-info", "-n", container.ID).CombinedOutput()
  998. if err != nil {
  999. return err
  1000. }
  1001. if !strings.Contains(string(output), "RUNNING") {
  1002. return nil
  1003. }
  1004. time.Sleep(500 * time.Millisecond)
  1005. }
  1006. }
  1007. func (container *Container) monitor() {
  1008. // Wait for the program to exit
  1009. // If the command does not exist, try to wait via lxc
  1010. // (This probably happens only for ghost containers, i.e. containers that were running when Docker started)
  1011. if container.cmd == nil {
  1012. utils.Debugf("monitor: waiting for container %s using waitLxc", container.ID)
  1013. if err := container.waitLxc(); err != nil {
  1014. utils.Errorf("monitor: while waiting for container %s, waitLxc had a problem: %s", container.ID, err)
  1015. }
  1016. } else {
  1017. utils.Debugf("monitor: waiting for container %s using cmd.Wait", container.ID)
  1018. if err := container.cmd.Wait(); err != nil {
  1019. // Since non-zero exit status and signal terminations will cause err to be non-nil,
  1020. // we have to actually discard it. Still, log it anyway, just in case.
  1021. utils.Debugf("monitor: cmd.Wait reported exit status %s for container %s", err, container.ID)
  1022. }
  1023. }
  1024. utils.Debugf("monitor: container %s finished", container.ID)
  1025. exitCode := -1
  1026. if container.cmd != nil {
  1027. exitCode = container.cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
  1028. }
  1029. if container.runtime != nil && container.runtime.srv != nil {
  1030. container.runtime.srv.LogEvent("die", container.ID, container.runtime.repositories.ImageName(container.Image))
  1031. }
  1032. // Cleanup
  1033. container.cleanup()
  1034. // Re-create a brand new stdin pipe once the container exited
  1035. if container.Config.OpenStdin {
  1036. container.stdin, container.stdinPipe = io.Pipe()
  1037. }
  1038. // Report status back
  1039. container.State.SetStopped(exitCode)
  1040. // Release the lock
  1041. close(container.waitLock)
  1042. if err := container.ToDisk(); err != nil {
  1043. // FIXME: there is a race condition here which causes this to fail during the unit tests.
  1044. // If another goroutine was waiting for Wait() to return before removing the container's root
  1045. // from the filesystem... At this point it may already have done so.
  1046. // This is because State.setStopped() has already been called, and has caused Wait()
  1047. // to return.
  1048. // FIXME: why are we serializing running state to disk in the first place?
  1049. //log.Printf("%s: Failed to dump configuration to the disk: %s", container.ID, err)
  1050. }
  1051. }
  1052. func (container *Container) cleanup() {
  1053. container.releaseNetwork()
  1054. // Disable all active links
  1055. if container.activeLinks != nil {
  1056. for _, link := range container.activeLinks {
  1057. link.Disable()
  1058. }
  1059. }
  1060. if container.Config.OpenStdin {
  1061. if err := container.stdin.Close(); err != nil {
  1062. utils.Errorf("%s: Error close stdin: %s", container.ID, err)
  1063. }
  1064. }
  1065. if err := container.stdout.CloseWriters(); err != nil {
  1066. utils.Errorf("%s: Error close stdout: %s", container.ID, err)
  1067. }
  1068. if err := container.stderr.CloseWriters(); err != nil {
  1069. utils.Errorf("%s: Error close stderr: %s", container.ID, err)
  1070. }
  1071. if container.ptyMaster != nil {
  1072. if err := container.ptyMaster.Close(); err != nil {
  1073. utils.Errorf("%s: Error closing Pty master: %s", container.ID, err)
  1074. }
  1075. }
  1076. if err := container.Unmount(); err != nil {
  1077. log.Printf("%v: Failed to umount filesystem: %v", container.ID, err)
  1078. }
  1079. }
  1080. func (container *Container) kill(sig int) error {
  1081. container.Lock()
  1082. defer container.Unlock()
  1083. if !container.State.IsRunning() {
  1084. return nil
  1085. }
  1086. if output, err := exec.Command("lxc-kill", "-n", container.ID, strconv.Itoa(sig)).CombinedOutput(); err != nil {
  1087. log.Printf("error killing container %s (%s, %s)", utils.TruncateID(container.ID), output, err)
  1088. return err
  1089. }
  1090. return nil
  1091. }
  1092. func (container *Container) Kill() error {
  1093. if !container.State.IsRunning() {
  1094. return nil
  1095. }
  1096. // 1. Send SIGKILL
  1097. if err := container.kill(9); err != nil {
  1098. return err
  1099. }
  1100. // 2. Wait for the process to die, in last resort, try to kill the process directly
  1101. if err := container.WaitTimeout(10 * time.Second); err != nil {
  1102. if container.cmd == nil {
  1103. return fmt.Errorf("lxc-kill failed, impossible to kill the container %s", utils.TruncateID(container.ID))
  1104. }
  1105. log.Printf("Container %s failed to exit within 10 seconds of lxc-kill %s - trying direct SIGKILL", "SIGKILL", utils.TruncateID(container.ID))
  1106. if err := container.cmd.Process.Kill(); err != nil {
  1107. return err
  1108. }
  1109. }
  1110. container.Wait()
  1111. return nil
  1112. }
  1113. func (container *Container) Stop(seconds int) error {
  1114. if !container.State.IsRunning() {
  1115. return nil
  1116. }
  1117. // 1. Send a SIGTERM
  1118. if err := container.kill(15); err != nil {
  1119. utils.Debugf("Error sending kill SIGTERM: %s", err)
  1120. log.Print("Failed to send SIGTERM to the process, force killing")
  1121. if err := container.kill(9); err != nil {
  1122. return err
  1123. }
  1124. }
  1125. // 2. Wait for the process to exit on its own
  1126. if err := container.WaitTimeout(time.Duration(seconds) * time.Second); err != nil {
  1127. log.Printf("Container %v failed to exit within %d seconds of SIGTERM - using the force", container.ID, seconds)
  1128. // 3. If it doesn't, then send SIGKILL
  1129. if err := container.Kill(); err != nil {
  1130. return err
  1131. }
  1132. }
  1133. return nil
  1134. }
  1135. func (container *Container) Restart(seconds int) error {
  1136. if err := container.Stop(seconds); err != nil {
  1137. return err
  1138. }
  1139. return container.Start()
  1140. }
  1141. // Wait blocks until the container stops running, then returns its exit code.
  1142. func (container *Container) Wait() int {
  1143. <-container.waitLock
  1144. return container.State.GetExitCode()
  1145. }
  1146. func (container *Container) Resize(h, w int) error {
  1147. pty, ok := container.ptyMaster.(*os.File)
  1148. if !ok {
  1149. return fmt.Errorf("ptyMaster does not have Fd() method")
  1150. }
  1151. return term.SetWinsize(pty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
  1152. }
  1153. func (container *Container) ExportRw() (archive.Archive, error) {
  1154. if err := container.EnsureMounted(); err != nil {
  1155. return nil, err
  1156. }
  1157. if container.runtime == nil {
  1158. return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID)
  1159. }
  1160. return container.runtime.Diff(container)
  1161. }
  1162. func (container *Container) Export() (archive.Archive, error) {
  1163. if err := container.EnsureMounted(); err != nil {
  1164. return nil, err
  1165. }
  1166. return archive.Tar(container.RootfsPath(), archive.Uncompressed)
  1167. }
  1168. func (container *Container) WaitTimeout(timeout time.Duration) error {
  1169. done := make(chan bool)
  1170. go func() {
  1171. container.Wait()
  1172. done <- true
  1173. }()
  1174. select {
  1175. case <-time.After(timeout):
  1176. return fmt.Errorf("Timed Out")
  1177. case <-done:
  1178. return nil
  1179. }
  1180. }
  1181. func (container *Container) EnsureMounted() error {
  1182. // FIXME: EnsureMounted is deprecated because drivers are now responsible
  1183. // for re-entrant mounting in their Get() method.
  1184. return container.Mount()
  1185. }
  1186. func (container *Container) Mount() error {
  1187. return container.runtime.Mount(container)
  1188. }
  1189. func (container *Container) Changes() ([]archive.Change, error) {
  1190. return container.runtime.Changes(container)
  1191. }
  1192. func (container *Container) GetImage() (*Image, error) {
  1193. if container.runtime == nil {
  1194. return nil, fmt.Errorf("Can't get image of unregistered container")
  1195. }
  1196. return container.runtime.graph.Get(container.Image)
  1197. }
  1198. func (container *Container) Unmount() error {
  1199. return container.runtime.Unmount(container)
  1200. }
  1201. func (container *Container) logPath(name string) string {
  1202. return path.Join(container.root, fmt.Sprintf("%s-%s.log", container.ID, name))
  1203. }
  1204. func (container *Container) ReadLog(name string) (io.Reader, error) {
  1205. return os.Open(container.logPath(name))
  1206. }
  1207. func (container *Container) hostConfigPath() string {
  1208. return path.Join(container.root, "hostconfig.json")
  1209. }
  1210. func (container *Container) jsonPath() string {
  1211. return path.Join(container.root, "config.json")
  1212. }
  1213. func (container *Container) EnvConfigPath() string {
  1214. return path.Join(container.root, "config.env")
  1215. }
  1216. func (container *Container) lxcConfigPath() string {
  1217. return path.Join(container.root, "config.lxc")
  1218. }
  1219. // This method must be exported to be used from the lxc template
  1220. func (container *Container) RootfsPath() string {
  1221. return container.rootfs
  1222. }
  1223. func validateID(id string) error {
  1224. if id == "" {
  1225. return fmt.Errorf("Invalid empty id")
  1226. }
  1227. return nil
  1228. }
  1229. // GetSize, return real size, virtual size
  1230. func (container *Container) GetSize() (int64, int64) {
  1231. var (
  1232. sizeRw, sizeRootfs int64
  1233. err error
  1234. driver = container.runtime.driver
  1235. )
  1236. if err := container.EnsureMounted(); err != nil {
  1237. utils.Errorf("Warning: failed to compute size of container rootfs %s: %s", container.ID, err)
  1238. return sizeRw, sizeRootfs
  1239. }
  1240. if differ, ok := container.runtime.driver.(graphdriver.Differ); ok {
  1241. sizeRw, err = differ.DiffSize(container.ID)
  1242. if err != nil {
  1243. utils.Errorf("Warning: driver %s couldn't return diff size of container %s: %s", driver, container.ID, err)
  1244. // FIXME: GetSize should return an error. Not changing it now in case
  1245. // there is a side-effect.
  1246. sizeRw = -1
  1247. }
  1248. } else {
  1249. changes, _ := container.Changes()
  1250. if changes != nil {
  1251. sizeRw = archive.ChangesSize(container.RootfsPath(), changes)
  1252. } else {
  1253. sizeRw = -1
  1254. }
  1255. }
  1256. if _, err = os.Stat(container.RootfsPath()); err != nil {
  1257. if sizeRootfs, err = utils.TreeSize(container.RootfsPath()); err != nil {
  1258. sizeRootfs = -1
  1259. }
  1260. }
  1261. return sizeRw, sizeRootfs
  1262. }
  1263. func (container *Container) Copy(resource string) (archive.Archive, error) {
  1264. if err := container.EnsureMounted(); err != nil {
  1265. return nil, err
  1266. }
  1267. var filter []string
  1268. basePath := path.Join(container.RootfsPath(), resource)
  1269. stat, err := os.Stat(basePath)
  1270. if err != nil {
  1271. return nil, err
  1272. }
  1273. if !stat.IsDir() {
  1274. d, f := path.Split(basePath)
  1275. basePath = d
  1276. filter = []string{f}
  1277. } else {
  1278. filter = []string{path.Base(basePath)}
  1279. basePath = path.Dir(basePath)
  1280. }
  1281. return archive.TarFilter(basePath, &archive.TarOptions{
  1282. Compression: archive.Uncompressed,
  1283. Includes: filter,
  1284. Recursive: true,
  1285. })
  1286. }
  1287. // Returns true if the container exposes a certain port
  1288. func (container *Container) Exposes(p Port) bool {
  1289. _, exists := container.Config.ExposedPorts[p]
  1290. return exists
  1291. }
  1292. func (container *Container) GetPtyMaster() (*os.File, error) {
  1293. if container.ptyMaster == nil {
  1294. return nil, ErrNoTTY
  1295. }
  1296. if pty, ok := container.ptyMaster.(*os.File); ok {
  1297. return pty, nil
  1298. }
  1299. return nil, ErrNotATTY
  1300. }