client_unix.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // +build linux solaris
  2. package libcontainerd
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "os"
  7. "path/filepath"
  8. "strings"
  9. "sync"
  10. containerd "github.com/containerd/containerd/api/grpc/types"
  11. "github.com/docker/docker/pkg/idtools"
  12. specs "github.com/opencontainers/runtime-spec/specs-go"
  13. "github.com/sirupsen/logrus"
  14. "golang.org/x/net/context"
  15. )
  16. func (clnt *client) prepareBundleDir(uid, gid int) (string, error) {
  17. root, err := filepath.Abs(clnt.remote.stateDir)
  18. if err != nil {
  19. return "", err
  20. }
  21. if uid == 0 && gid == 0 {
  22. return root, nil
  23. }
  24. p := string(filepath.Separator)
  25. for _, d := range strings.Split(root, string(filepath.Separator))[1:] {
  26. p = filepath.Join(p, d)
  27. fi, err := os.Stat(p)
  28. if err != nil && !os.IsNotExist(err) {
  29. return "", err
  30. }
  31. if os.IsNotExist(err) || fi.Mode()&1 == 0 {
  32. p = fmt.Sprintf("%s.%d.%d", p, uid, gid)
  33. if err := idtools.MkdirAndChown(p, 0700, idtools.IDPair{uid, gid}); err != nil && !os.IsExist(err) {
  34. return "", err
  35. }
  36. }
  37. }
  38. return p, nil
  39. }
  40. func (clnt *client) Create(containerID string, checkpoint string, checkpointDir string, spec specs.Spec, attachStdio StdioCallback, options ...CreateOption) (err error) {
  41. clnt.lock(containerID)
  42. defer clnt.unlock(containerID)
  43. if _, err := clnt.getContainer(containerID); err == nil {
  44. return fmt.Errorf("Container %s is already active", containerID)
  45. }
  46. uid, gid, err := getRootIDs(spec)
  47. if err != nil {
  48. return err
  49. }
  50. dir, err := clnt.prepareBundleDir(uid, gid)
  51. if err != nil {
  52. return err
  53. }
  54. container := clnt.newContainer(filepath.Join(dir, containerID), options...)
  55. if err := container.clean(); err != nil {
  56. return err
  57. }
  58. defer func() {
  59. if err != nil {
  60. container.clean()
  61. clnt.deleteContainer(containerID)
  62. }
  63. }()
  64. if err := idtools.MkdirAllAndChown(container.dir, 0700, idtools.IDPair{uid, gid}); err != nil && !os.IsExist(err) {
  65. return err
  66. }
  67. f, err := os.Create(filepath.Join(container.dir, configFilename))
  68. if err != nil {
  69. return err
  70. }
  71. defer f.Close()
  72. if err := json.NewEncoder(f).Encode(spec); err != nil {
  73. return err
  74. }
  75. return container.start(&spec, checkpoint, checkpointDir, attachStdio)
  76. }
  77. func (clnt *client) Signal(containerID string, sig int) error {
  78. clnt.lock(containerID)
  79. defer clnt.unlock(containerID)
  80. _, err := clnt.remote.apiClient.Signal(context.Background(), &containerd.SignalRequest{
  81. Id: containerID,
  82. Pid: InitFriendlyName,
  83. Signal: uint32(sig),
  84. })
  85. return err
  86. }
  87. func (clnt *client) newContainer(dir string, options ...CreateOption) *container {
  88. container := &container{
  89. containerCommon: containerCommon{
  90. process: process{
  91. dir: dir,
  92. processCommon: processCommon{
  93. containerID: filepath.Base(dir),
  94. client: clnt,
  95. friendlyName: InitFriendlyName,
  96. },
  97. },
  98. processes: make(map[string]*process),
  99. },
  100. }
  101. for _, option := range options {
  102. if err := option.Apply(container); err != nil {
  103. logrus.Errorf("libcontainerd: newContainer(): %v", err)
  104. }
  105. }
  106. return container
  107. }
  108. type exitNotifier struct {
  109. id string
  110. client *client
  111. c chan struct{}
  112. once sync.Once
  113. }
  114. func (en *exitNotifier) close() {
  115. en.once.Do(func() {
  116. close(en.c)
  117. en.client.mapMutex.Lock()
  118. if en == en.client.exitNotifiers[en.id] {
  119. delete(en.client.exitNotifiers, en.id)
  120. }
  121. en.client.mapMutex.Unlock()
  122. })
  123. }
  124. func (en *exitNotifier) wait() <-chan struct{} {
  125. return en.c
  126. }