snapshot_service.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. package snapshot_service
  2. import (
  3. "context"
  4. "net"
  5. "os"
  6. "path"
  7. "strings"
  8. snapshotsapi "github.com/containerd/containerd/api/services/snapshots/v1"
  9. "github.com/containerd/containerd/contrib/snapshotservice"
  10. "github.com/containerd/containerd/mount"
  11. "github.com/containerd/containerd/snapshots"
  12. "github.com/containerd/containerd/snapshots/overlay"
  13. "google.golang.org/grpc"
  14. "yunion.io/x/jsonutils"
  15. "yunion.io/x/log"
  16. "yunion.io/x/pkg/errors"
  17. )
  18. func StartService(guestMan IGuestManager, root string) error {
  19. sn, err := NewSnapshotter(guestMan, root)
  20. if err != nil {
  21. return errors.Wrap(err, "NewSnapshotter")
  22. }
  23. svc := snapshotservice.FromSnapshotter(sn)
  24. rpc := grpc.NewServer()
  25. snapshotsapi.RegisterSnapshotsServer(rpc, svc)
  26. socksPath := path.Join(root, SocksFileName)
  27. if err := os.RemoveAll(socksPath); err != nil {
  28. return errors.Wrapf(err, "RemoveAll %s", socksPath)
  29. }
  30. listener, err := net.Listen("unix", socksPath)
  31. if err != nil {
  32. return errors.Wrapf(err, "Listen %s", socksPath)
  33. }
  34. return rpc.Serve(listener)
  35. }
  36. type IGuestManager interface {
  37. GetContainerManager(serverId string) (ISnapshotContainerManager, error)
  38. }
  39. type ISnapshotContainerManager interface {
  40. GetRootFsMountPath(containerId string) (string, error)
  41. }
  42. func NewSnapshotter(guestMan IGuestManager, root string, opts ...overlay.Opt) (snapshots.Snapshotter, error) {
  43. sn, err := overlay.NewSnapshotter(root, opts...)
  44. if err != nil {
  45. return nil, errors.Wrap(err, "NewSnapshotter")
  46. }
  47. return &overlayRootFsUpperSnapshotter{
  48. Snapshotter: sn,
  49. guestMan: guestMan,
  50. }, nil
  51. }
  52. type overlayRootFsUpperSnapshotter struct {
  53. snapshots.Snapshotter
  54. guestMan IGuestManager
  55. }
  56. func (s *overlayRootFsUpperSnapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, error) {
  57. info, err := s.Snapshotter.Stat(ctx, key)
  58. if err != nil {
  59. return nil, errors.Wrapf(err, "Stat with %s", key)
  60. }
  61. infoJson := jsonutils.Marshal(info)
  62. log.Infof("mount request info: %s", infoJson.String())
  63. mounts, err := s.Snapshotter.Mounts(ctx, key)
  64. if err != nil {
  65. return nil, errors.Wrapf(err, "Mounts with %s", key)
  66. }
  67. mounts, err = s.changeUpper(ctx, key, mounts)
  68. if err != nil {
  69. return nil, errors.Wrapf(err, "Mounts.changeUpper with %s", key)
  70. }
  71. return mounts, nil
  72. }
  73. func (s *overlayRootFsUpperSnapshotter) Prepare(ctx context.Context, key string, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) {
  74. mounts, err := s.Snapshotter.Prepare(ctx, key, parent, opts...)
  75. if err != nil {
  76. return nil, errors.Wrapf(err, "Prepare with %s", key)
  77. }
  78. infoJson := jsonutils.Marshal(mounts)
  79. log.Debugf("prepare request key: %s, parent: %s, mounts: %s", key, parent, infoJson.String())
  80. mounts, err = s.changeUpper(ctx, key, mounts)
  81. if err != nil {
  82. return nil, errors.Wrapf(err, "Prepare.changeUpper with %s", key)
  83. }
  84. return mounts, nil
  85. }
  86. func (s *overlayRootFsUpperSnapshotter) View(ctx context.Context, key string, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) {
  87. mounts, err := s.Snapshotter.View(ctx, key, parent, opts...)
  88. if err != nil {
  89. return nil, errors.Wrapf(err, "View with %s", key)
  90. }
  91. infoJson := jsonutils.Marshal(mounts)
  92. log.Debugf("view request key: %s, parent: %s, info: %s", key, parent, infoJson.String())
  93. mounts, err = s.changeUpper(ctx, key, mounts)
  94. if err != nil {
  95. return nil, errors.Wrapf(err, "View.changeUpper with %s", key)
  96. }
  97. return mounts, nil
  98. }
  99. func (s *overlayRootFsUpperSnapshotter) changeUpper(ctx context.Context, key string, mounts []mount.Mount) ([]mount.Mount, error) {
  100. if len(mounts) != 1 || mounts[0].Type != "overlay" {
  101. return mounts, nil
  102. }
  103. info, err := s.Snapshotter.Stat(ctx, key)
  104. if err != nil {
  105. return nil, errors.Wrapf(err, "Stat with %s", key)
  106. }
  107. log.Debugf("change upper key: %s, info: %s", key, jsonutils.Marshal(info))
  108. serverId, ok := info.Labels[LabelServerId]
  109. if !ok || serverId == "" {
  110. return mounts, nil
  111. }
  112. containerId, ok := info.Labels[LabelContainerId]
  113. if !ok || containerId == "" {
  114. return mounts, nil
  115. }
  116. ctrMan, err := s.guestMan.GetContainerManager(serverId)
  117. if err != nil {
  118. return mounts, errors.Wrapf(err, "GetContainerManager with %s", serverId)
  119. }
  120. rootFsPath, err := ctrMan.GetRootFsMountPath(containerId)
  121. if err != nil {
  122. return mounts, errors.Wrapf(err, "GetRootFsMountPath with %s, %s", serverId, containerId)
  123. }
  124. log.Debugf("changeUpper: rootFsPath: %s , container: %s", rootFsPath, containerId)
  125. upperPath := path.Join(rootFsPath, "upper")
  126. workPath := path.Join(rootFsPath, "work")
  127. for _, dir := range []string{upperPath, workPath} {
  128. if err := os.MkdirAll(dir, 0755); err != nil {
  129. return mounts, errors.Wrapf(err, "MkdirAll %s", dir)
  130. }
  131. }
  132. upperDirKey := "upperdir="
  133. workDirKey := "workdir="
  134. for i, o := range mounts[0].Options {
  135. if strings.HasPrefix(o, upperDirKey) {
  136. mounts[0].Options[i] = upperDirKey + upperPath
  137. }
  138. if strings.HasPrefix(o, workDirKey) {
  139. mounts[0].Options[i] = workDirKey + workPath
  140. }
  141. }
  142. return mounts, nil
  143. }