bundle.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // +build linux
  2. /*
  3. Copyright The containerd Authors.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. package linux
  15. import (
  16. "context"
  17. "fmt"
  18. "io/ioutil"
  19. "os"
  20. "path/filepath"
  21. "github.com/containerd/containerd/events/exchange"
  22. "github.com/containerd/containerd/runtime/linux/runctypes"
  23. "github.com/containerd/containerd/runtime/v1/shim"
  24. "github.com/containerd/containerd/runtime/v1/shim/client"
  25. "github.com/pkg/errors"
  26. )
  27. // loadBundle loads an existing bundle from disk
  28. func loadBundle(id, path, workdir string) *bundle {
  29. return &bundle{
  30. id: id,
  31. path: path,
  32. workDir: workdir,
  33. }
  34. }
  35. // newBundle creates a new bundle on disk at the provided path for the given id
  36. func newBundle(id, path, workDir string, spec []byte) (b *bundle, err error) {
  37. if err := os.MkdirAll(path, 0711); err != nil {
  38. return nil, err
  39. }
  40. path = filepath.Join(path, id)
  41. if err := os.Mkdir(path, 0711); err != nil {
  42. return nil, err
  43. }
  44. defer func() {
  45. if err != nil {
  46. os.RemoveAll(path)
  47. }
  48. }()
  49. workDir = filepath.Join(workDir, id)
  50. if err := os.MkdirAll(workDir, 0711); err != nil {
  51. return nil, err
  52. }
  53. defer func() {
  54. if err != nil {
  55. os.RemoveAll(workDir)
  56. }
  57. }()
  58. if err := os.Mkdir(filepath.Join(path, "rootfs"), 0711); err != nil {
  59. return nil, err
  60. }
  61. err = ioutil.WriteFile(filepath.Join(path, configFilename), spec, 0666)
  62. return &bundle{
  63. id: id,
  64. path: path,
  65. workDir: workDir,
  66. }, err
  67. }
  68. type bundle struct {
  69. id string
  70. path string
  71. workDir string
  72. }
  73. // ShimOpt specifies shim options for initialization and connection
  74. type ShimOpt func(*bundle, string, *runctypes.RuncOptions) (shim.Config, client.Opt)
  75. // ShimRemote is a ShimOpt for connecting and starting a remote shim
  76. func ShimRemote(c *Config, daemonAddress, cgroup string, exitHandler func()) ShimOpt {
  77. return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) {
  78. config := b.shimConfig(ns, c, ropts)
  79. return config,
  80. client.WithStart(c.Shim, b.shimAddress(ns), daemonAddress, cgroup, c.ShimDebug, exitHandler)
  81. }
  82. }
  83. // ShimLocal is a ShimOpt for using an in process shim implementation
  84. func ShimLocal(c *Config, exchange *exchange.Exchange) ShimOpt {
  85. return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) {
  86. return b.shimConfig(ns, c, ropts), client.WithLocal(exchange)
  87. }
  88. }
  89. // ShimConnect is a ShimOpt for connecting to an existing remote shim
  90. func ShimConnect(c *Config, onClose func()) ShimOpt {
  91. return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) {
  92. return b.shimConfig(ns, c, ropts), client.WithConnect(b.shimAddress(ns), onClose)
  93. }
  94. }
  95. // NewShimClient connects to the shim managing the bundle and tasks creating it if needed
  96. func (b *bundle) NewShimClient(ctx context.Context, namespace string, getClientOpts ShimOpt, runcOpts *runctypes.RuncOptions) (*client.Client, error) {
  97. cfg, opt := getClientOpts(b, namespace, runcOpts)
  98. return client.New(ctx, cfg, opt)
  99. }
  100. // Delete deletes the bundle from disk
  101. func (b *bundle) Delete() error {
  102. err := atomicDelete(b.path)
  103. if err == nil {
  104. return atomicDelete(b.workDir)
  105. }
  106. // error removing the bundle path; still attempt removing work dir
  107. err2 := atomicDelete(b.workDir)
  108. if err2 == nil {
  109. return err
  110. }
  111. return errors.Wrapf(err, "Failed to remove both bundle and workdir locations: %v", err2)
  112. }
  113. func (b *bundle) shimAddress(namespace string) string {
  114. return filepath.Join(string(filepath.Separator), "containerd-shim", namespace, b.id, "shim.sock")
  115. }
  116. func (b *bundle) shimConfig(namespace string, c *Config, runcOptions *runctypes.RuncOptions) shim.Config {
  117. var (
  118. criuPath string
  119. runtimeRoot = c.RuntimeRoot
  120. systemdCgroup bool
  121. )
  122. if runcOptions != nil {
  123. criuPath = runcOptions.CriuPath
  124. systemdCgroup = runcOptions.SystemdCgroup
  125. if runcOptions.RuntimeRoot != "" {
  126. runtimeRoot = runcOptions.RuntimeRoot
  127. }
  128. }
  129. return shim.Config{
  130. Path: b.path,
  131. WorkDir: b.workDir,
  132. Namespace: namespace,
  133. Criu: criuPath,
  134. RuntimeRoot: runtimeRoot,
  135. SystemdCgroup: systemdCgroup,
  136. }
  137. }
  138. // atomicDelete renames the path to a hidden file before removal
  139. func atomicDelete(path string) error {
  140. // create a hidden dir for an atomic removal
  141. atomicPath := filepath.Join(filepath.Dir(path), fmt.Sprintf(".%s", filepath.Base(path)))
  142. if err := os.Rename(path, atomicPath); err != nil {
  143. return err
  144. }
  145. return os.RemoveAll(atomicPath)
  146. }