Skip to content

Commit b2f7f22

Browse files
fix(gms): rewrite GMS checkpoint/restore operator support (ai-dynamo#8194)
Co-authored-by: Dmitry Tokarev <dtokarev@nvidia.com>
1 parent 2d86b81 commit b2f7f22

33 files changed

Lines changed: 933 additions & 1573 deletions

deploy/operator/internal/checkpoint/checkpoint_test.go

Lines changed: 14 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323

2424
nvidiacomv1alpha1 "github.com/ai-dynamo/dynamo/deploy/operator/api/v1alpha1"
2525
"github.com/ai-dynamo/dynamo/deploy/operator/internal/consts"
26-
gmsruntime "github.com/ai-dynamo/dynamo/deploy/operator/internal/gms"
26+
gms "github.com/ai-dynamo/dynamo/deploy/operator/internal/gms"
2727
snapshotprotocol "github.com/ai-dynamo/dynamo/deploy/snapshot/protocol"
2828
"github.com/stretchr/testify/assert"
2929
"github.com/stretchr/testify/require"
@@ -183,50 +183,6 @@ func TestCreateOrGetAutoCheckpointSetsDefaultArtifactVersion(t *testing.T) {
183183

184184
// --- InjectCheckpointIntoPodSpec tests ---
185185

186-
func TestEnsurePodInfoVolumeMergesExistingDownwardAPIItems(t *testing.T) {
187-
podSpec := &corev1.PodSpec{
188-
Volumes: []corev1.Volume{{
189-
Name: consts.PodInfoVolumeName,
190-
VolumeSource: corev1.VolumeSource{
191-
DownwardAPI: &corev1.DownwardAPIVolumeSource{
192-
Items: []corev1.DownwardAPIVolumeFile{
193-
{
194-
Path: "pod_name",
195-
FieldRef: &corev1.ObjectFieldSelector{FieldPath: "metadata.name"},
196-
},
197-
{
198-
Path: "custom",
199-
FieldRef: &corev1.ObjectFieldSelector{FieldPath: "metadata.labels['custom']"},
200-
},
201-
},
202-
},
203-
},
204-
}},
205-
}
206-
207-
EnsurePodInfoVolume(podSpec)
208-
209-
require.Len(t, podSpec.Volumes, 1)
210-
require.NotNil(t, podSpec.Volumes[0].DownwardAPI)
211-
212-
fields := map[string]string{}
213-
for _, item := range podSpec.Volumes[0].DownwardAPI.Items {
214-
if item.FieldRef != nil {
215-
fields[item.Path] = item.FieldRef.FieldPath
216-
}
217-
}
218-
219-
assert.Equal(t, consts.PodInfoFieldPodName, fields["pod_name"])
220-
assert.Equal(t, consts.PodInfoFieldPodUID, fields["pod_uid"])
221-
assert.Equal(t, consts.PodInfoFieldPodNamespace, fields["pod_namespace"])
222-
assert.Equal(t, "metadata.labels['custom']", fields["custom"])
223-
assert.Equal(t, "metadata.labels['"+consts.KubeLabelDynamoNamespace+"']", fields[consts.PodInfoFileDynNamespace])
224-
assert.Equal(t, "metadata.labels['"+consts.KubeLabelDynamoWorkerHash+"']", fields[consts.PodInfoFileDynNamespaceWorkerSuffix])
225-
assert.Equal(t, "metadata.labels['"+consts.KubeLabelDynamoComponentType+"']", fields[consts.PodInfoFileDynComponent])
226-
assert.Equal(t, "metadata.labels['"+consts.KubeLabelDynamoGraphDeploymentName+"']", fields[consts.PodInfoFileDynParentDGDName])
227-
assert.Equal(t, consts.PodInfoFieldPodNamespace, fields[consts.PodInfoFileDynParentDGDNamespace])
228-
}
229-
230186
func TestInjectCheckpointIntoPodSpec(t *testing.T) {
231187
t.Run("ready checkpoint injects podinfo and overrides command", func(t *testing.T) {
232188
podSpec := testPodSpec()
@@ -263,65 +219,21 @@ func TestInjectCheckpointIntoPodSpec(t *testing.T) {
263219
assert.Equal(t, consts.PodInfoMountPath, mountPaths[consts.PodInfoVolumeName])
264220
})
265221

266-
t.Run("ready checkpoint augments existing podinfo volume", func(t *testing.T) {
267-
podSpec := testPodSpec()
268-
podSpec.Volumes = append(podSpec.Volumes, corev1.Volume{
269-
Name: consts.PodInfoVolumeName,
270-
VolumeSource: corev1.VolumeSource{
271-
DownwardAPI: &corev1.DownwardAPIVolumeSource{
272-
Items: []corev1.DownwardAPIVolumeFile{
273-
{Path: "pod_name", FieldRef: &corev1.ObjectFieldSelector{FieldPath: consts.PodInfoFieldPodName}},
274-
{Path: "pod_uid", FieldRef: &corev1.ObjectFieldSelector{FieldPath: consts.PodInfoFieldPodUID}},
275-
{Path: "pod_namespace", FieldRef: &corev1.ObjectFieldSelector{FieldPath: consts.PodInfoFieldPodNamespace}},
276-
},
277-
},
278-
},
279-
})
280-
info := &CheckpointInfo{Enabled: true, Ready: true, Identity: ptr.To(testIdentity())}
281-
reader := fake.NewClientBuilder().WithScheme(testScheme()).WithObjects(testSnapshotAgentDaemonSet()).Build()
282-
require.NoError(t, InjectCheckpointIntoPodSpec(context.Background(), reader, testNamespace, podSpec, info))
283-
284-
var podInfoVolume *corev1.Volume
285-
for i := range podSpec.Volumes {
286-
if podSpec.Volumes[i].Name == consts.PodInfoVolumeName {
287-
podInfoVolume = &podSpec.Volumes[i]
288-
break
289-
}
290-
}
291-
require.NotNil(t, podInfoVolume)
292-
require.NotNil(t, podInfoVolume.DownwardAPI)
293-
294-
fields := map[string]string{}
295-
for _, item := range podInfoVolume.DownwardAPI.Items {
296-
if item.FieldRef != nil {
297-
fields[item.Path] = item.FieldRef.FieldPath
298-
}
299-
}
300-
assert.Equal(t, consts.PodInfoFieldPodName, fields["pod_name"])
301-
assert.Equal(t, consts.PodInfoFieldPodUID, fields["pod_uid"])
302-
assert.Equal(t, consts.PodInfoFieldPodNamespace, fields["pod_namespace"])
303-
assert.Equal(t, "metadata.labels['"+consts.KubeLabelDynamoNamespace+"']", fields[consts.PodInfoFileDynNamespace])
304-
assert.Equal(t, "metadata.labels['"+consts.KubeLabelDynamoWorkerHash+"']", fields[consts.PodInfoFileDynNamespaceWorkerSuffix])
305-
assert.Equal(t, "metadata.labels['"+consts.KubeLabelDynamoComponentType+"']", fields[consts.PodInfoFileDynComponent])
306-
assert.Equal(t, "metadata.labels['"+consts.KubeLabelDynamoGraphDeploymentName+"']", fields[consts.PodInfoFileDynParentDGDName])
307-
assert.Equal(t, consts.PodInfoFieldPodNamespace, fields[consts.PodInfoFileDynParentDGDNamespace])
308-
})
309-
310222
t.Run("ready checkpoint targets the container named main", func(t *testing.T) {
311223
podSpec := &corev1.PodSpec{
312224
Containers: []corev1.Container{
225+
{Name: "main", Image: "main:latest", Command: []string{"python3"}, Args: []string{"-m", "dynamo.vllm"}},
313226
{Name: "sidecar", Image: "sidecar:latest", Command: []string{"sidecar"}, Args: []string{"run"}},
314-
{Name: consts.MainContainerName, Image: "main:latest", Command: []string{"python3"}, Args: []string{"-m", "dynamo.vllm"}},
315227
},
316228
}
317229
info := &CheckpointInfo{Enabled: true, Ready: true, Hash: testHash}
318230
reader := fake.NewClientBuilder().WithScheme(testScheme()).WithObjects(testSnapshotAgentDaemonSet()).Build()
319231

320232
require.NoError(t, InjectCheckpointIntoPodSpec(context.Background(), reader, testNamespace, podSpec, info))
321-
assert.Equal(t, []string{"sidecar"}, podSpec.Containers[0].Command)
322-
assert.Equal(t, []string{"run"}, podSpec.Containers[0].Args)
323-
assert.Equal(t, []string{"sleep", "infinity"}, podSpec.Containers[1].Command)
324-
assert.Nil(t, podSpec.Containers[1].Args)
233+
assert.Equal(t, []string{"sleep", "infinity"}, podSpec.Containers[0].Command)
234+
assert.Nil(t, podSpec.Containers[0].Args)
235+
assert.Equal(t, []string{"sidecar"}, podSpec.Containers[1].Command)
236+
assert.Equal(t, []string{"run"}, podSpec.Containers[1].Args)
325237
})
326238

327239
t.Run("ready gms checkpoint injects restore sidecars and loader mount", func(t *testing.T) {
@@ -331,22 +243,24 @@ func TestInjectCheckpointIntoPodSpec(t *testing.T) {
331243
reader := fake.NewClientBuilder().WithScheme(testScheme()).WithObjects(testSnapshotAgentDaemonSet()).Build()
332244

333245
require.NoError(t, InjectCheckpointIntoPodSpec(context.Background(), reader, testNamespace, podSpec, info))
334-
gmsServer := findContainer(podSpec, gmsruntime.ServerContainerName)
246+
gmsServer := findContainer(podSpec, gms.ServerContainerName)
335247
require.NotNil(t, gmsServer)
336248
loader := findContainer(podSpec, GMSLoaderContainer)
337249
require.NotNil(t, loader)
338250

339-
// Restore: gms-server should be a regular container, not an init container
340-
assert.Empty(t, podSpec.InitContainers, "restore pods should not have gms-server as init container")
341-
assert.Nil(t, gmsServer.RestartPolicy, "restore gms-server should not have RestartPolicy")
251+
// Restore: server and loader are init sidecars (restartPolicy=Always)
252+
assert.NotNil(t, gmsServer.RestartPolicy, "restore gms-server should have RestartPolicy")
253+
assert.Equal(t, corev1.ContainerRestartPolicyAlways, *gmsServer.RestartPolicy)
342254
assert.Nil(t, gmsServer.StartupProbe, "restore gms-server should not have StartupProbe")
255+
assert.NotNil(t, loader.RestartPolicy, "restore gms-loader should have RestartPolicy")
256+
assert.Equal(t, corev1.ContainerRestartPolicyAlways, *loader.RestartPolicy)
343257

344258
mounts := map[string]string{}
345259
for _, mount := range loader.VolumeMounts {
346260
mounts[mount.Name] = mount.MountPath
347261
}
348262
assert.Equal(t, "/checkpoints", mounts[snapshotprotocol.CheckpointVolumeName])
349-
assert.Equal(t, gmsruntime.SharedMountPath, mounts[gmsruntime.SharedVolumeName])
263+
assert.Equal(t, gms.SharedMountPath, mounts[gms.SharedVolumeName])
350264

351265
env := map[string]string{}
352266
for _, item := range loader.Env {
@@ -366,8 +280,7 @@ func TestInjectCheckpointIntoPodSpec(t *testing.T) {
366280
errMsg string
367281
}{
368282
{"hash empty and identity nil", testPodSpec(), &CheckpointInfo{Enabled: true}, fake.NewClientBuilder().WithScheme(testScheme()).WithObjects(testSnapshotAgentDaemonSet()).Build(), "identity is nil"},
369-
{"no containers", &corev1.PodSpec{}, testInfo(), fake.NewClientBuilder().WithScheme(testScheme()).WithObjects(testSnapshotAgentDaemonSet()).Build(), "no container found"},
370-
{"main container missing", &corev1.PodSpec{Containers: []corev1.Container{{Name: "sidecar", Image: "img", Command: []string{"python3"}}}}, testInfo(), fake.NewClientBuilder().WithScheme(testScheme()).WithObjects(testSnapshotAgentDaemonSet()).Build(), "main container not found"},
283+
{"no containers", &corev1.PodSpec{}, testInfo(), fake.NewClientBuilder().WithScheme(testScheme()).WithObjects(testSnapshotAgentDaemonSet()).Build(), "no container named"},
371284
{"snapshot daemonset missing", testPodSpec(), testInfo(), fake.NewClientBuilder().WithScheme(testScheme()).Build(), "no snapshot-agent daemonset found"},
372285
} {
373286
t.Run(tc.name, func(t *testing.T) {

0 commit comments

Comments
 (0)