Unverified Commit 70a8aa3f authored by Thomas Montfort's avatar Thomas Montfort Committed by GitHub
Browse files

feat(operator): mechanism for disabling imagePullSecrets discovery (#3092)


Signed-off-by: default avatartmontfort <tmontfort@nvidia.com>
parent 6675bfc8
......@@ -30,6 +30,8 @@ const (
KubeAnnotationEnableGrove = "nvidia.com/enable-grove"
KubeAnnotationDisableImagePullSecretDiscovery = "nvidia.com/disable-image-pull-secret-discovery"
KubeLabelDynamoGraphDeploymentName = "nvidia.com/dynamo-graph-deployment-name"
KubeLabelDynamoComponent = "nvidia.com/dynamo-component"
KubeLabelDynamoNamespace = "nvidia.com/dynamo-namespace"
......
......@@ -765,8 +765,10 @@ func GenerateBasePodSpec(
maps.Copy(container.Resources.Limits, overrideResources.Limits)
}
shouldDisableImagePullSecret := component.Annotations[commonconsts.KubeAnnotationDisableImagePullSecretDiscovery] == commonconsts.KubeLabelValueTrue
imagePullSecrets := []corev1.LocalObjectReference{}
if secretsRetriever != nil && component.ExtraPodSpec != nil && component.ExtraPodSpec.MainContainer != nil && component.ExtraPodSpec.MainContainer.Image != "" {
if !shouldDisableImagePullSecret && secretsRetriever != nil && component.ExtraPodSpec != nil && component.ExtraPodSpec.MainContainer != nil && component.ExtraPodSpec.MainContainer.Image != "" {
secretsName, err := secretsRetriever.GetSecrets(namespace, component.ExtraPodSpec.MainContainer.Image)
if err == nil {
for _, secretName := range secretsName {
......
......@@ -3141,6 +3141,20 @@ func (m *mockSecretsRetriever) GetSecrets(namespace, registry string) ([]string,
return []string{}, nil
}
// Mock SecretsRetriever that returns secrets for testing docker secrets functionality
type mockSecretsRetrieverWithSecrets struct{}
func (m *mockSecretsRetrieverWithSecrets) RetrieveImagePullSecrets(ctx context.Context, deployment *v1alpha1.DynamoGraphDeployment) ([]corev1.LocalObjectReference, error) {
return []corev1.LocalObjectReference{
{Name: "test-docker-secret"},
}, nil
}
func (m *mockSecretsRetrieverWithSecrets) GetSecrets(namespace, registry string) ([]string, error) {
// Return some mock secrets when called
return []string{"test-docker-secret"}, nil
}
func TestGeneratePodSpecForComponent_SGLang(t *testing.T) {
secretsRetriever := &mockSecretsRetriever{}
dynamoDeployment := &v1alpha1.DynamoGraphDeployment{
......@@ -4484,6 +4498,138 @@ func TestGenerateBasePodSpec_PlannerServiceAccount(t *testing.T) {
}
}
func TestGenerateBasePodSpec_DisableImagePullSecretDiscovery(t *testing.T) {
tests := []struct {
name string
component *v1alpha1.DynamoComponentDeploymentOverridesSpec
secretsRetriever SecretsRetriever
expectedImagePullSecrets []corev1.LocalObjectReference
}{
{
name: "disable docker secrets annotation set to true",
component: &v1alpha1.DynamoComponentDeploymentOverridesSpec{
DynamoComponentDeploymentSharedSpec: v1alpha1.DynamoComponentDeploymentSharedSpec{
ComponentType: commonconsts.ComponentTypeFrontend,
Annotations: map[string]string{
commonconsts.KubeAnnotationDisableImagePullSecretDiscovery: commonconsts.KubeLabelValueTrue,
},
ExtraPodSpec: &common.ExtraPodSpec{
MainContainer: &corev1.Container{
Image: "test-registry/test-image:latest",
},
},
},
},
secretsRetriever: &mockSecretsRetrieverWithSecrets{},
expectedImagePullSecrets: nil, // Should be nil when disabled
},
{
name: "disable docker secrets annotation set to false",
component: &v1alpha1.DynamoComponentDeploymentOverridesSpec{
DynamoComponentDeploymentSharedSpec: v1alpha1.DynamoComponentDeploymentSharedSpec{
ComponentType: commonconsts.ComponentTypeFrontend,
Annotations: map[string]string{
commonconsts.KubeAnnotationDisableImagePullSecretDiscovery: commonconsts.KubeLabelValueFalse,
},
ExtraPodSpec: &common.ExtraPodSpec{
MainContainer: &corev1.Container{
Image: "test-registry/test-image:latest",
},
},
},
},
secretsRetriever: &mockSecretsRetrieverWithSecrets{},
expectedImagePullSecrets: []corev1.LocalObjectReference{
{Name: "test-docker-secret"},
}, // Should be present when enabled
},
{
name: "disable docker secrets annotation not set (default behavior)",
component: &v1alpha1.DynamoComponentDeploymentOverridesSpec{
DynamoComponentDeploymentSharedSpec: v1alpha1.DynamoComponentDeploymentSharedSpec{
ComponentType: commonconsts.ComponentTypeFrontend,
ExtraPodSpec: &common.ExtraPodSpec{
MainContainer: &corev1.Container{
Image: "test-registry/test-image:latest",
},
},
},
},
secretsRetriever: &mockSecretsRetrieverWithSecrets{},
expectedImagePullSecrets: []corev1.LocalObjectReference{
{Name: "test-docker-secret"},
}, // Should be present by default
},
{
name: "disable docker secrets annotation set to invalid value",
component: &v1alpha1.DynamoComponentDeploymentOverridesSpec{
DynamoComponentDeploymentSharedSpec: v1alpha1.DynamoComponentDeploymentSharedSpec{
ComponentType: commonconsts.ComponentTypeFrontend,
Annotations: map[string]string{
commonconsts.KubeAnnotationDisableImagePullSecretDiscovery: "invalid",
},
ExtraPodSpec: &common.ExtraPodSpec{
MainContainer: &corev1.Container{
Image: "test-registry/test-image:latest",
},
},
},
},
secretsRetriever: &mockSecretsRetrieverWithSecrets{},
expectedImagePullSecrets: []corev1.LocalObjectReference{
{Name: "test-docker-secret"},
}, // Should be present when annotation is not "true"
},
{
name: "disable docker secrets but no secrets retriever",
component: &v1alpha1.DynamoComponentDeploymentOverridesSpec{
DynamoComponentDeploymentSharedSpec: v1alpha1.DynamoComponentDeploymentSharedSpec{
ComponentType: commonconsts.ComponentTypeFrontend,
Annotations: map[string]string{
commonconsts.KubeAnnotationDisableImagePullSecretDiscovery: commonconsts.KubeLabelValueFalse,
},
ExtraPodSpec: &common.ExtraPodSpec{
MainContainer: &corev1.Container{
Image: "test-registry/test-image:latest",
},
},
},
},
secretsRetriever: nil,
expectedImagePullSecrets: nil, // Should be nil when no retriever
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
controllerConfig := controller_common.Config{}
podSpec, err := GenerateBasePodSpec(
tt.component,
BackendFrameworkNoop,
tt.secretsRetriever,
"test-deployment",
"default",
RoleMain,
1,
controllerConfig,
commonconsts.MultinodeDeploymentTypeGrove,
"test-service",
)
if err != nil {
t.Errorf("GenerateBasePodSpec() error = %v", err)
return
}
if !reflect.DeepEqual(podSpec.ImagePullSecrets, tt.expectedImagePullSecrets) {
t.Errorf("GenerateBasePodSpec() ImagePullSecrets = %v, want %v",
podSpec.ImagePullSecrets, tt.expectedImagePullSecrets)
}
})
}
}
func TestGenerateBasePodSpec_Worker(t *testing.T) {
secretsRetriever := &mockSecretsRetriever{}
controllerConfig := controller_common.Config{}
......
......@@ -130,4 +130,38 @@ If you are a Dynamo contributor the [dynamo run guide](../dynamo_run.md) for det
```yaml
args:
- --is-prefill-worker # For disaggregated prefill workers
```
\ No newline at end of file
```
### Image Pull Secret Configuration
#### Automatic Discovery and Injection
By default, the Dynamo operator automatically discovers and injects image pull secrets based on container registry host matching. The operator scans Docker config secrets within the same namespace and matches their registry hostnames to the container image URLs, automatically injecting the appropriate secrets into the pod's `imagePullSecrets`.
**Disabling Automatic Discovery:**
To disable this behavior for a component and manually control image pull secrets:
```yaml
YourWorker:
dynamoNamespace: your-namespace
componentType: worker
annotations:
nvidia.com/disable-image-pull-secret-discovery: "true"
```
When disabled, you can manually specify secrets as you would for a normal pod spec via:
```yaml
YourWorker:
dynamoNamespace: your-namespace
componentType: worker
annotations:
nvidia.com/disable-image-pull-secret-discovery: "true"
extraPodSpec:
imagePullSecrets:
- name: my-registry-secret
- name: another-secret
mainContainer:
image: your-image
```
This automatic discovery eliminates the need to manually configure image pull secrets for each deployment.
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment