Skip to content

Commit 72e54a7

Browse files
committed
Add additional metadata to inspect and checkpoint
This commit adds additional metadata to the inspect command if checkpointing support is active. The following three fields are added to inspect: "checkpointedAt": timestamp, "restored": true or false With "checkpointedAt" it is possible to see when a checkpoint was created. "restored" is true if the container has been restored from a checkpoint for all other container this is set to false. Signed-off-by: Adrian Reber <[email protected]>
1 parent a9d845a commit 72e54a7

13 files changed

+467
-136
lines changed

internal/lib/checkpoint.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"io"
77
"os"
88
"path/filepath"
9+
"time"
910

1011
metadata "github.com/checkpoint-restore/checkpointctl/lib"
1112
"github.com/checkpoint-restore/go-criu/v6/stats"
@@ -19,18 +20,15 @@ import (
1920
"github.com/opencontainers/runtime-tools/generate"
2021
)
2122

22-
type ContainerCheckpointRestoreOptions struct {
23-
Container string
24-
Pod string
25-
26-
libpod.ContainerCheckpointOptions
27-
}
28-
2923
// ContainerCheckpoint checkpoints a running container.
30-
func (c *ContainerServer) ContainerCheckpoint(ctx context.Context, opts *ContainerCheckpointRestoreOptions) (string, error) {
31-
ctr, err := c.LookupContainer(ctx, opts.Container)
24+
func (c *ContainerServer) ContainerCheckpoint(
25+
ctx context.Context,
26+
config *metadata.ContainerConfig,
27+
opts *libpod.ContainerCheckpointOptions,
28+
) (string, error) {
29+
ctr, err := c.LookupContainer(ctx, config.ID)
3230
if err != nil {
33-
return "", fmt.Errorf("failed to find container %s: %w", opts.Container, err)
31+
return "", fmt.Errorf("failed to find container %s: %w", config.ID, err)
3432
}
3533

3634
configFile := filepath.Join(ctr.BundlePath(), "config.json")
@@ -164,6 +162,8 @@ func (c *ContainerServer) prepareCheckpointExport(ctr *oci.Container) error {
164162
}
165163
return c.config.DefaultRuntime
166164
}(),
165+
CheckpointedAt: time.Now(),
166+
Restored: ctr.Restore(),
167167
}
168168

169169
if _, err := metadata.WriteJSONFile(config, ctr.Dir(), metadata.ConfigDumpFile); err != nil {

internal/lib/checkpoint_test.go

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import (
55
"fmt"
66
"os"
77

8+
metadata "github.com/checkpoint-restore/checkpointctl/lib"
9+
"github.com/containers/podman/v4/libpod"
810
"github.com/containers/podman/v4/pkg/criu"
911
cstorage "github.com/containers/storage"
1012
"github.com/containers/storage/pkg/archive"
11-
"github.com/cri-o/cri-o/internal/lib"
1213
"github.com/cri-o/cri-o/internal/oci"
1314
"github.com/golang/mock/gomock"
1415
. "github.com/onsi/ginkgo/v2"
@@ -35,14 +36,19 @@ var _ = t.Describe("ContainerCheckpoint", func() {
3536
t.Describe("ContainerCheckpoint", func() {
3637
It("should fail with container not running", func() {
3738
// Given
38-
var opts lib.ContainerCheckpointRestoreOptions
3939

4040
addContainerAndSandbox()
4141

42-
opts.Container = containerID
42+
config := &metadata.ContainerConfig{
43+
ID: containerID,
44+
}
4345

4446
// When
45-
res, err := sut.ContainerCheckpoint(context.Background(), &opts)
47+
res, err := sut.ContainerCheckpoint(
48+
context.Background(),
49+
config,
50+
&libpod.ContainerCheckpointOptions{},
51+
)
4652

4753
// Then
4854
Expect(err).NotTo(BeNil())
@@ -53,10 +59,10 @@ var _ = t.Describe("ContainerCheckpoint", func() {
5359
t.Describe("ContainerCheckpoint", func() {
5460
It("should succeed", func() {
5561
// Given
56-
var opts lib.ContainerCheckpointRestoreOptions
57-
5862
addContainerAndSandbox()
59-
opts.Container = containerID
63+
config := &metadata.ContainerConfig{
64+
ID: containerID,
65+
}
6066

6167
myContainer.SetState(&oci.ContainerState{
6268
State: specs.State{Status: oci.ContainerStateRunning},
@@ -69,29 +75,38 @@ var _ = t.Describe("ContainerCheckpoint", func() {
6975
)
7076

7177
// When
72-
res, err := sut.ContainerCheckpoint(context.Background(), &opts)
78+
res, err := sut.ContainerCheckpoint(
79+
context.Background(),
80+
config,
81+
&libpod.ContainerCheckpointOptions{},
82+
)
7383

7484
// Then
7585
Expect(err).To(BeNil())
76-
Expect(res).To(Equal(opts.Container))
86+
Expect(res).To(Equal(config.ID))
7787
})
7888
})
7989
t.Describe("ContainerCheckpoint", func() {
8090
It("should fail because runtime failure (/bin/false)", func() {
8191
// Given
8292
mockRuncToFalseInLibConfig()
83-
var opts lib.ContainerCheckpointRestoreOptions
8493

8594
addContainerAndSandbox()
86-
opts.Container = containerID
95+
config := &metadata.ContainerConfig{
96+
ID: containerID,
97+
}
8798

8899
myContainer.SetState(&oci.ContainerState{
89100
State: specs.State{Status: oci.ContainerStateRunning},
90101
})
91102
myContainer.SetSpec(&specs.Spec{Version: "1.0.0"})
92103

93104
// When
94-
_, err := sut.ContainerCheckpoint(context.Background(), &opts)
105+
_, err := sut.ContainerCheckpoint(
106+
context.Background(),
107+
config,
108+
&libpod.ContainerCheckpointOptions{},
109+
)
95110

96111
// Then
97112
Expect(err).ToNot(BeNil())
@@ -101,8 +116,6 @@ var _ = t.Describe("ContainerCheckpoint", func() {
101116
t.Describe("ContainerCheckpoint", func() {
102117
It("should fail with export", func() {
103118
// Given
104-
var opts lib.ContainerCheckpointRestoreOptions
105-
106119
// Overwrite container config to add external bind mounts
107120
tmpFile, err := os.CreateTemp("", "restore-test-file")
108121
Expect(err).To(BeNil())
@@ -138,8 +151,12 @@ var _ = t.Describe("ContainerCheckpoint", func() {
138151
Expect(os.WriteFile("config.json", []byte(containerConfig), 0o644)).To(BeNil())
139152

140153
addContainerAndSandbox()
141-
opts.Container = containerID
142-
opts.TargetFile = "cp.tar"
154+
config := &metadata.ContainerConfig{
155+
ID: containerID,
156+
}
157+
opts := &libpod.ContainerCheckpointOptions{
158+
TargetFile: "cp.tar",
159+
}
143160
defer os.RemoveAll("cp.tar")
144161

145162
myContainer.SetState(&oci.ContainerState{
@@ -156,20 +173,20 @@ var _ = t.Describe("ContainerCheckpoint", func() {
156173
)
157174

158175
// When
159-
res, err := sut.ContainerCheckpoint(context.Background(), &opts)
176+
res, err := sut.ContainerCheckpoint(context.Background(), config, opts)
160177

161178
// Then
162179
Expect(err).To(BeNil())
163-
Expect(res).To(ContainSubstring(opts.Container))
180+
Expect(res).To(ContainSubstring(config.ID))
164181
})
165182
})
166183
t.Describe("ContainerCheckpoint", func() {
167184
It("should fail during unmount", func() {
168185
// Given
169-
var opts lib.ContainerCheckpointRestoreOptions
170-
171186
addContainerAndSandbox()
172-
opts.Container = containerID
187+
config := &metadata.ContainerConfig{
188+
ID: containerID,
189+
}
173190

174191
myContainer.SetState(&oci.ContainerState{
175192
State: specs.State{Status: oci.ContainerStateRunning},
@@ -182,7 +199,11 @@ var _ = t.Describe("ContainerCheckpoint", func() {
182199
)
183200

184201
// When
185-
_, err := sut.ContainerCheckpoint(context.Background(), &opts)
202+
_, err := sut.ContainerCheckpoint(
203+
context.Background(),
204+
config,
205+
&libpod.ContainerCheckpointOptions{},
206+
)
186207

187208
// Then
188209
Expect(err.Error()).To(Equal(`failed to unmount container containerID: error`))
@@ -197,11 +218,16 @@ var _ = t.Describe("ContainerCheckpoint", func() {
197218
t.Describe("ContainerCheckpoint", func() {
198219
It("should fail with invalid container ID", func() {
199220
// Given
200-
var opts lib.ContainerCheckpointRestoreOptions
201-
opts.Container = "invalid"
221+
config := &metadata.ContainerConfig{
222+
ID: "invalid",
223+
}
202224

203225
// When
204-
res, err := sut.ContainerCheckpoint(context.Background(), &opts)
226+
res, err := sut.ContainerCheckpoint(
227+
context.Background(),
228+
config,
229+
&libpod.ContainerCheckpointOptions{},
230+
)
205231

206232
// Then
207233
Expect(err).NotTo(BeNil())
@@ -212,14 +238,17 @@ var _ = t.Describe("ContainerCheckpoint", func() {
212238
t.Describe("ContainerCheckpoint", func() {
213239
It("should fail with invalid config", func() {
214240
// Given
215-
var opts lib.ContainerCheckpointRestoreOptions
216-
217241
addContainerAndSandbox()
218-
219-
opts.Container = containerID
242+
config := &metadata.ContainerConfig{
243+
ID: containerID,
244+
}
220245

221246
// When
222-
res, err := sut.ContainerCheckpoint(context.Background(), &opts)
247+
res, err := sut.ContainerCheckpoint(
248+
context.Background(),
249+
config,
250+
&libpod.ContainerCheckpointOptions{},
251+
)
223252

224253
// Then
225254
Expect(err).NotTo(BeNil())

internal/lib/restore.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
metadata "github.com/checkpoint-restore/checkpointctl/lib"
1010
"github.com/checkpoint-restore/go-criu/v6/stats"
11+
"github.com/containers/podman/v4/libpod"
1112
"github.com/containers/podman/v4/pkg/annotations"
1213
"github.com/containers/podman/v4/pkg/checkpoint/crutils"
1314
"github.com/containers/storage/pkg/archive"
@@ -18,12 +19,16 @@ import (
1819
)
1920

2021
// ContainerRestore restores a checkpointed container.
21-
func (c *ContainerServer) ContainerRestore(ctx context.Context, opts *ContainerCheckpointRestoreOptions) (string, error) {
22+
func (c *ContainerServer) ContainerRestore(
23+
ctx context.Context,
24+
config *metadata.ContainerConfig,
25+
opts *libpod.ContainerCheckpointOptions,
26+
) (string, error) {
2227
var ctr *oci.Container
2328
var err error
24-
ctr, err = c.LookupContainer(ctx, opts.Container)
29+
ctr, err = c.LookupContainer(ctx, config.ID)
2530
if err != nil {
26-
return "", fmt.Errorf("failed to find container %s: %w", opts.Container, err)
31+
return "", fmt.Errorf("failed to find container %s: %w", config.ID, err)
2732
}
2833

2934
cStatus := ctr.State()
@@ -48,12 +53,7 @@ func (c *ContainerServer) ContainerRestore(ctx context.Context, opts *ContainerC
4853
log.Debugf(ctx, "Container mountpoint %v", mountPoint)
4954
log.Debugf(ctx, "Sandbox %v", ctr.Sandbox())
5055
log.Debugf(ctx, "Specgen.Config.Annotations[io.kubernetes.cri-o.SandboxID] %v", ctrSpec.Config.Annotations["io.kubernetes.cri-o.SandboxID"])
51-
// If there was no podID specified this will restore the container
52-
// in its original sandbox
53-
if opts.Pod == "" {
54-
opts.Pod = ctr.Sandbox()
55-
}
56-
sb, err := c.LookupSandbox(opts.Pod)
56+
sb, err := c.LookupSandbox(ctr.Sandbox())
5757
if err != nil {
5858
return "", err
5959
}
@@ -225,7 +225,7 @@ func (c *ContainerServer) ContainerRestore(ctx context.Context, opts *ContainerC
225225
// Update Sandbox Name
226226
ctrSpec.AddAnnotation(annotations.SandboxName, sb.Name())
227227
// Update Sandbox ID
228-
ctrSpec.AddAnnotation(annotations.SandboxID, opts.Pod)
228+
ctrSpec.AddAnnotation(annotations.SandboxID, ctr.Sandbox())
229229

230230
mData := fmt.Sprintf(
231231
"k8s_%s_%s_%s_%s0",
@@ -236,7 +236,7 @@ func (c *ContainerServer) ContainerRestore(ctx context.Context, opts *ContainerC
236236
)
237237
ctrSpec.AddAnnotation(annotations.Name, mData)
238238

239-
ctr.SetSandbox(opts.Pod)
239+
ctr.SetSandbox(ctr.Sandbox())
240240

241241
saveOptions := generate.ExportOptions{}
242242
if err := ctrSpec.SaveToFile(filepath.Join(ctr.Dir(), "config.json"), saveOptions); err != nil {

0 commit comments

Comments
 (0)