container_restore_opts.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. Copyright The containerd Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package containerd
  14. import (
  15. "context"
  16. "errors"
  17. "fmt"
  18. "github.com/containerd/containerd/containers"
  19. "github.com/containerd/containerd/content"
  20. "github.com/containerd/containerd/images"
  21. "github.com/containerd/containerd/protobuf/proto"
  22. ptypes "github.com/containerd/containerd/protobuf/types"
  23. "github.com/opencontainers/image-spec/identity"
  24. imagespec "github.com/opencontainers/image-spec/specs-go/v1"
  25. )
  26. var (
  27. // ErrImageNameNotFoundInIndex is returned when the image name is not found in the index
  28. ErrImageNameNotFoundInIndex = errors.New("image name not found in index")
  29. // ErrRuntimeNameNotFoundInIndex is returned when the runtime is not found in the index
  30. ErrRuntimeNameNotFoundInIndex = errors.New("runtime not found in index")
  31. // ErrSnapshotterNameNotFoundInIndex is returned when the snapshotter is not found in the index
  32. ErrSnapshotterNameNotFoundInIndex = errors.New("snapshotter not found in index")
  33. )
  34. // RestoreOpts are options to manage the restore operation
  35. type RestoreOpts func(context.Context, string, *Client, Image, *imagespec.Index) NewContainerOpts
  36. // WithRestoreImage restores the image for the container
  37. func WithRestoreImage(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts {
  38. return func(ctx context.Context, client *Client, c *containers.Container) error {
  39. name, ok := index.Annotations[checkpointImageNameLabel]
  40. if !ok || name == "" {
  41. return ErrImageNameNotFoundInIndex
  42. }
  43. snapshotter, ok := index.Annotations[checkpointSnapshotterNameLabel]
  44. if !ok || name == "" {
  45. return ErrSnapshotterNameNotFoundInIndex
  46. }
  47. i, err := client.GetImage(ctx, name)
  48. if err != nil {
  49. return err
  50. }
  51. diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), client.platform)
  52. if err != nil {
  53. return err
  54. }
  55. parent := identity.ChainID(diffIDs).String()
  56. if _, err := client.SnapshotService(snapshotter).Prepare(ctx, id, parent); err != nil {
  57. return err
  58. }
  59. c.Image = i.Name()
  60. c.SnapshotKey = id
  61. c.Snapshotter = snapshotter
  62. return nil
  63. }
  64. }
  65. // WithRestoreRuntime restores the runtime for the container
  66. func WithRestoreRuntime(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts {
  67. return func(ctx context.Context, client *Client, c *containers.Container) error {
  68. name, ok := index.Annotations[checkpointRuntimeNameLabel]
  69. if !ok {
  70. return ErrRuntimeNameNotFoundInIndex
  71. }
  72. // restore options if present
  73. m, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointRuntimeOptions)
  74. if err != nil {
  75. if err != ErrMediaTypeNotFound {
  76. return err
  77. }
  78. }
  79. var options ptypes.Any
  80. if m != nil {
  81. store := client.ContentStore()
  82. data, err := content.ReadBlob(ctx, store, *m)
  83. if err != nil {
  84. return fmt.Errorf("unable to read checkpoint runtime: %w", err)
  85. }
  86. if err := proto.Unmarshal(data, &options); err != nil {
  87. return err
  88. }
  89. }
  90. c.Runtime = containers.RuntimeInfo{
  91. Name: name,
  92. Options: &options,
  93. }
  94. return nil
  95. }
  96. }
  97. // WithRestoreSpec restores the spec from the checkpoint for the container
  98. func WithRestoreSpec(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts {
  99. return func(ctx context.Context, client *Client, c *containers.Container) error {
  100. m, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointConfig)
  101. if err != nil {
  102. return err
  103. }
  104. store := client.ContentStore()
  105. data, err := content.ReadBlob(ctx, store, *m)
  106. if err != nil {
  107. return fmt.Errorf("unable to read checkpoint config: %w", err)
  108. }
  109. var any ptypes.Any
  110. if err := proto.Unmarshal(data, &any); err != nil {
  111. return err
  112. }
  113. c.Spec = &any
  114. return nil
  115. }
  116. }
  117. // WithRestoreRW restores the rw layer from the checkpoint for the container
  118. func WithRestoreRW(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts {
  119. return func(ctx context.Context, client *Client, c *containers.Container) error {
  120. // apply rw layer
  121. rw, err := GetIndexByMediaType(index, imagespec.MediaTypeImageLayerGzip)
  122. if err != nil {
  123. return err
  124. }
  125. mounts, err := client.SnapshotService(c.Snapshotter).Mounts(ctx, c.SnapshotKey)
  126. if err != nil {
  127. return err
  128. }
  129. if _, err := client.DiffService().Apply(ctx, *rw, mounts); err != nil {
  130. return err
  131. }
  132. return nil
  133. }
  134. }