@@ -109,10 +109,12 @@ var _ = Describe("NemoCustomizer Controller", func() {
109
109
Expect (err ).ToNot (HaveOccurred ())
110
110
trainingCM := loadConfigMapFromFile (filepath .Join (testDataDir , "training_config.yaml" ))
111
111
modelsCM := loadConfigMapFromFile (filepath .Join (testDataDir , "models_config.yaml" ))
112
+ modelTargetsCM := loadConfigMapFromFile (filepath .Join (testDataDir , "models_config_targets.yaml" ))
112
113
113
114
// Register the test ConfigMaps in the cluster
114
115
Expect (reconciler .GetClient ().Create (ctx , trainingCM )).To (Succeed ())
115
116
Expect (reconciler .GetClient ().Create (ctx , modelsCM )).To (Succeed ())
117
+ Expect (reconciler .GetClient ().Create (ctx , modelTargetsCM )).To (Succeed ())
116
118
117
119
nemoCustomizer = & appsv1alpha1.NemoCustomizer {
118
120
ObjectMeta : metav1.ObjectMeta {
@@ -365,6 +367,13 @@ var _ = Describe("NemoCustomizer Controller", func() {
365
367
if err := k8sClient .Get (ctx , modelsCMName , modelsCM ); err == nil {
366
368
Expect (k8sClient .Delete (ctx , modelsCM )).To (Succeed ())
367
369
}
370
+
371
+ // Delete the models targets config
372
+ modelTargetsCMName := types.NamespacedName {Name : "nemo-model-target-config" , Namespace : "default" }
373
+ modelTargetsCM := & corev1.ConfigMap {}
374
+ if err := k8sClient .Get (ctx , modelTargetsCMName , modelTargetsCM ); err == nil {
375
+ Expect (k8sClient .Delete (ctx , modelTargetsCM )).To (Succeed ())
376
+ }
368
377
})
369
378
370
379
Describe ("Reconcile" , func () {
@@ -575,6 +584,74 @@ var _ = Describe("NemoCustomizer Controller", func() {
575
584
Expect (parsed ).To (HaveKeyWithValue ("mlflow_tracking_url" , "http://mlflow-tracking.nemo.svc.cluster.local:80" ))
576
585
})
577
586
587
+ It ("should create customizer config with model targets and templates" , func () {
588
+ namespacedName := types.NamespacedName {Name : nemoCustomizer .Name , Namespace : "default" }
589
+
590
+ // use models config map with targets and templates
591
+ nemoCustomizer .Spec .Models .Name = "nemo-model-config-targets"
592
+
593
+ err := client .Create (context .TODO (), nemoCustomizer )
594
+ Expect (err ).NotTo (HaveOccurred ())
595
+ err = client .Create (context .TODO (), secrets )
596
+ Expect (err ).NotTo (HaveOccurred ())
597
+
598
+ result , err := reconciler .Reconcile (context .TODO (), reconcile.Request {NamespacedName : namespacedName })
599
+ Expect (err ).NotTo (HaveOccurred ())
600
+ Expect (result ).To (Equal (ctrl.Result {}))
601
+
602
+ err = client .Get (ctx , namespacedName , nemoCustomizer )
603
+ Expect (err ).ToNot (HaveOccurred ())
604
+ Expect (nemoCustomizer .Finalizers ).To (ContainElement (NemoCustomizerFinalizer ))
605
+
606
+ // Check that the customizer config map was created
607
+ configMap := & corev1.ConfigMap {}
608
+ err = client .Get (context .TODO (), types.NamespacedName {
609
+ Name : nemoCustomizer .Name ,
610
+ Namespace : nemoCustomizer .Namespace ,
611
+ }, configMap )
612
+ Expect (err ).NotTo (HaveOccurred ())
613
+
614
+ // Verify metadata
615
+ Expect (configMap .Name ).To (Equal (nemoCustomizer .GetName ()))
616
+ Expect (configMap .Namespace ).To (Equal (nemoCustomizer .Namespace ))
617
+ // Verify key exists
618
+ Expect (configMap .Data ).To (HaveKey ("config.yaml" ))
619
+ configData := configMap .Data ["config.yaml" ]
620
+ Expect (configData ).NotTo (BeEmpty ())
621
+
622
+ // Verify presence of top-level keys
623
+ Expect (configData ).To (ContainSubstring ("training:" ))
624
+ Expect (configData ).To (ContainSubstring ("customizationTargets:" ))
625
+ Expect (configData ).To (ContainSubstring ("customizationConfigTemplates:" ))
626
+ Expect (configData ).ToNot (ContainSubstring ("models:" )) // "models" is deprecated from NMR v25.06
627
+ Expect (configData ).To (ContainSubstring ("model_download_jobs:" ))
628
+
629
+ // Unmarshal the full merged config
630
+ var parsed map [string ]interface {}
631
+ err = yaml .Unmarshal ([]byte (configData ), & parsed )
632
+ Expect (err ).NotTo (HaveOccurred ())
633
+
634
+ // Validate model download jobs config with new secret params from NMR v25.06
635
+ training , ok := parsed ["model_download_jobs" ].(map [string ]interface {})
636
+ Expect (ok ).To (BeTrue (), "expected 'training' to be a map" )
637
+ Expect (training ).To (HaveKey ("ngcSecretName" ))
638
+ Expect (training ).To (HaveKey ("ngcSecretKey" ))
639
+
640
+ // Validate model targets
641
+ modelTargets , ok := parsed ["customizationTargets" ].(map [string ]interface {})
642
+ Expect (ok ).To (BeTrue (), "expected 'modelTargets' to be a map" )
643
+ Expect (modelTargets ).To (HaveKey ("targets" ))
644
+
645
+ // Validate model config templates
646
+ configTemplates , ok := parsed ["customizationConfigTemplates" ].(map [string ]interface {})
647
+ Expect (ok ).To (BeTrue (), "expected 'configTemplates' to be a map" )
648
+ Expect (configTemplates ).To (HaveKey ("templates" ))
649
+
650
+ Expect (parsed ).To (HaveKeyWithValue ("entity_store_url" , "http://nemoentitystore-sample.nemo.svc.cluster.local:8000" ))
651
+ Expect (parsed ).To (HaveKeyWithValue ("nemo_data_store_url" , "http://nemodatastore-sample.nemo.svc.cluster.local:8000" ))
652
+ Expect (parsed ).To (HaveKeyWithValue ("mlflow_tracking_url" , "http://mlflow-tracking.nemo.svc.cluster.local:80" ))
653
+ })
654
+
578
655
It ("should delete HPA when NemoCustomizer is updated" , func () {
579
656
namespacedName := types.NamespacedName {Name : nemoCustomizer .Name , Namespace : "default" }
580
657
err := client .Create (context .TODO (), nemoCustomizer )
0 commit comments