Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions deploy/operator/internal/dynamo/failover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,8 @@ func intraPodFailoverPodSpec() corev1.PodSpec {
{Name: "DYN_SYSTEM_USE_ENDPOINT_HEALTH_STATUS", Value: "true"},
{Name: "DYN_HEALTH_CHECK_ENABLED", Value: "true"},
{Name: commonconsts.DynamoDiscoveryBackendEnvVar, Value: "kubernetes"},
{Name: "CONTAINER_NAME", Value: commonconsts.MainContainerName},
{Name: "DYN_KUBE_DISCOVERY_MODE", Value: "container"},
{Name: "TMPDIR", Value: gms.SharedMountPath},
},
Ports: []corev1.ContainerPort{
Expand Down Expand Up @@ -555,15 +557,18 @@ func TestBuildFailoverPod_RejectsNonVLLM(t *testing.T) {
}

func TestBuildFailoverPod_EngineEnvVars(t *testing.T) {
t.Log("Build the active-passive engine containers from a container-discovery base")
ps := intraPodFailoverPodSpec()
err := buildFailoverPod(&ps, 1, BackendFrameworkVLLM)
require.NoError(t, err)

t.Log("Verify each engine keeps container discovery and receives its own container identity")
for i := range 2 {
engine := ps.Containers[i]
env := envToMap(engine.Env)
assert.Equal(t, strconv.Itoa(i), env["ENGINE_ID"], "engine-%d ENGINE_ID", i)
assert.Equal(t, fmt.Sprintf("engine-%d", i), env["CONTAINER_NAME"], "engine-%d CONTAINER_NAME", i)
assert.Equal(t, "container", env["DYN_KUBE_DISCOVERY_MODE"], "engine-%d discovery mode", i)
assert.Equal(t, intraPodFailoverLockFile, env["FAILOVER_LOCK_PATH"], "engine-%d FAILOVER_LOCK_PATH", i)
assert.Equal(t, "notready", env["DYN_SYSTEM_STARTING_HEALTH_STATUS"], "engine-%d starting health", i)
assert.Equal(t, "true", env["DYN_SYSTEM_ENABLED"], "engine-%d system enabled", i)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package validation_test

import (
"maps"
"testing"

nvidiacomv1alpha1 "github.com/ai-dynamo/dynamo/deploy/operator/api/v1alpha1"
Expand Down Expand Up @@ -59,6 +60,7 @@ func TestDynamoComponentDeploymentValidator_Validate(t *testing.T) {
wantCELErr string
wantWebhookErrs []string
wantWarnings []string
wantPodAnnotations map[string]string
}{
// Baseline schema and webhook behavior.
{
Expand Down Expand Up @@ -871,15 +873,21 @@ func TestDynamoComponentDeploymentValidator_Validate(t *testing.T) {
wantCELErr: "spec.podTemplate.metadata.annotations: Invalid value: podTemplate backend annotation must be mp or ray, case-insensitively",
},
{
name: "v1beta1 valid pod template backend annotation reaches the webhook",
// Generated DCD pod metadata must survive structural pruning.
name: "v1beta1 discovery annotation survives the generated DCD API server round trip",
deployment: betaDCDForAdmission(func(dcd *nvidiacomv1beta1.DynamoComponentDeployment) {
dcd.Spec.PodTemplate = &corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
consts.KubeAnnotationVLLMDistributedExecutorBackend: "RaY",
consts.KubeAnnotationDynamoKubeDiscoveryMode: "container",
}},
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: consts.MainContainerName}}},
}
}),
wantPodAnnotations: map[string]string{
consts.KubeAnnotationVLLMDistributedExecutorBackend: "RaY",
consts.KubeAnnotationDynamoKubeDiscoveryMode: "container",
},
},
{
name: "v1alpha1 invalid extra pod metadata annotation reaches the webhook",
Expand Down Expand Up @@ -1016,7 +1024,20 @@ func TestDynamoComponentDeploymentValidator_Validate(t *testing.T) {
seedGates.Checkpoint = true
test.seedGates = &seedGates
}
runAdmissionTest(t, test)
actual := runAdmissionTest(t, test)
if tt.wantPodAnnotations != nil {
t.Log("Verify the API server preserved embedded pod-template annotations")
var actualDCD nvidiacomv1beta1.DynamoComponentDeployment
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(actual.Object, &actualDCD); err != nil {
t.Fatalf("convert admitted DCD: %v", err)
}
if actualDCD.Spec.PodTemplate == nil {
t.Fatal("admitted DCD has no spec.podTemplate")
}
if got := actualDCD.Spec.PodTemplate.Annotations; !maps.Equal(got, tt.wantPodAnnotations) {
t.Fatalf("spec.podTemplate.metadata.annotations = %v, want %v", got, tt.wantPodAnnotations)
}
}
})
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package validation_test

import (
"fmt"
"maps"
"strings"
"testing"

Expand Down Expand Up @@ -56,12 +57,13 @@ func TestDynamoGraphDeploymentValidator_Validate(t *testing.T) {
checkpointOff bool // disables checkpoint creation and restore
username string // supplies the admission request identity

wantSchemaErr string
wantCELErr string
wantAdmissionErrs []string
wantWebhookErrs []string
wantWarnings []string
notWantErr string
wantSchemaErr string
wantCELErr string
wantAdmissionErrs []string
wantWebhookErrs []string
wantWarnings []string
notWantErr string
wantPodAnnotations map[string]string
}{
// Baseline create-path rules.
{
Expand Down Expand Up @@ -295,15 +297,21 @@ func TestDynamoGraphDeploymentValidator_Validate(t *testing.T) {
wantCELErr: "spec.components[1].podTemplate.metadata.annotations: Invalid value: podTemplate backend annotation must be mp or ray, case-insensitively",
},
{
name: "v1beta1 valid pod template backend annotation reaches the webhook",
// Component pod metadata must survive structural pruning.
name: "v1beta1 discovery annotation survives the component pod template API server round trip",
deployment: betaDGDForAdmission(func(dgd *nvidiacomv1beta1.DynamoGraphDeployment) {
betaWorkerComponent(dgd).PodTemplate = &corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{
consts.KubeAnnotationVLLMDistributedExecutorBackend: "RaY",
consts.KubeAnnotationDynamoKubeDiscoveryMode: "container",
}},
Spec: corev1.PodSpec{Containers: []corev1.Container{{Name: consts.MainContainerName}}},
}
}),
wantPodAnnotations: map[string]string{
consts.KubeAnnotationVLLMDistributedExecutorBackend: "RaY",
consts.KubeAnnotationDynamoKubeDiscoveryMode: "container",
},
},
{
name: "v1alpha1 converted extraPodMetadata annotation does not receive v1beta1 CEL validation",
Expand Down Expand Up @@ -1658,7 +1666,26 @@ func TestDynamoGraphDeploymentValidator_Validate(t *testing.T) {
test.seedGates = &seedGates
}
}
runAdmissionTest(t, test)
actual := runAdmissionTest(t, test)
if tt.wantPodAnnotations != nil {
t.Log("Verify the API server preserved embedded component pod-template annotations")
var actualDGD nvidiacomv1beta1.DynamoGraphDeployment
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(actual.Object, &actualDGD); err != nil {
t.Fatalf("convert admitted DGD: %v", err)
}
component := actualDGD.GetComponentByName(dgdAdmissionWorkerName)
if component == nil || component.PodTemplate == nil {
t.Fatalf("admitted DGD has no pod template for component %q", dgdAdmissionWorkerName)
}
if got := component.PodTemplate.Annotations; !maps.Equal(got, tt.wantPodAnnotations) {
t.Fatalf(
"spec.components[%q].podTemplate.metadata.annotations = %v, want %v",
dgdAdmissionWorkerName,
got,
tt.wantPodAnnotations,
)
}
}
})
}
}
Expand Down
Loading