@@ -35,6 +35,7 @@ import (
3535 k8swait "k8s.io/apimachinery/pkg/util/wait"
3636 "k8s.io/klog/v2"
3737 "sigs.k8s.io/controller-runtime/pkg/client"
38+ "sigs.k8s.io/yaml"
3839
3940 "github.com/google/go-cmp/cmp"
4041 depnodes "github.com/k8stopologyawareschedwg/deployer/pkg/clientutil/nodes"
@@ -55,13 +56,16 @@ import (
5556 "github.com/openshift-kni/numaresources-operator/pkg/validation"
5657 rteconfig "github.com/openshift-kni/numaresources-operator/rte/pkg/config"
5758 "github.com/openshift-kni/numaresources-operator/test/e2e/label"
59+ e2eclient "github.com/openshift-kni/numaresources-operator/test/internal/clients"
5860 "github.com/openshift-kni/numaresources-operator/test/internal/configuration"
5961 e2efixture "github.com/openshift-kni/numaresources-operator/test/internal/fixture"
6062 e2enrt "github.com/openshift-kni/numaresources-operator/test/internal/noderesourcetopologies"
6163 "github.com/openshift-kni/numaresources-operator/test/internal/nrosched"
6264 "github.com/openshift-kni/numaresources-operator/test/internal/objects"
6365
6466 serialconfig "github.com/openshift-kni/numaresources-operator/test/e2e/serial/config"
67+ "github.com/openshift-kni/numaresources-operator/test/internal/hypershift"
68+ "github.com/openshift-kni/numaresources-operator/test/internal/nodepools"
6569)
6670
6771/*
@@ -83,6 +87,14 @@ type mcpInfo struct {
8387 sampleNode corev1.Node
8488}
8589
90+ type Tuning struct {
91+ Profile struct {
92+ CPU struct {
93+ TopologyManagerPolicy string `yaml:"topologyManagerPolicy"`
94+ } `yaml:"cpu"`
95+ } `yaml:"profile"`
96+ }
97+
8698func (i mcpInfo ) ToString () string {
8799 mcpname := ""
88100 if i .mcpObj != nil {
@@ -285,6 +297,90 @@ var _ = Describe("[serial][disruptive] numaresources configuration management",
285297 Expect (schedOK ).To (BeTrue (), "pod %s/%s not scheduled with expected scheduler %s" , updatedPod .Namespace , updatedPod .Name , serialconfig .SchedulerTestName )
286298 })
287299
300+ It ("[test_id:80821] Verify Performance Profile updates on management cluster reflect in NRT resources" , Label ("reboot_required" , label .Slow , label .HyperShift ), func () {
301+ fxt .IsRebootTest = true
302+
303+ By ("fetching the initial TM policy set in NRT" )
304+ initialNrtList := nrtv1alpha2.NodeResourceTopologyList {}
305+ initialNrtList , err := e2enrt .GetUpdated (fxt .Client , initialNrtList , timeout )
306+ Expect (err ).ToNot (HaveOccurred (), "cannot get any NodeResourceTopology object from the cluster" )
307+ Expect (initialNrtList .Items ).ToNot (BeEmpty (), "no NodeResourceTopology items found" )
308+
309+ initialNrt := initialNrtList .Items [0 ]
310+ var initialTMPolicy string
311+ for _ , attr := range initialNrt .Attributes {
312+ if attr .Name == "topologyManagerPolicy" {
313+ initialTMPolicy = attr .Value
314+ break
315+ }
316+ }
317+ Expect (initialTMPolicy ).ToNot (BeEmpty (), "topologyManagerPolicy not found in initial NRT" )
318+ newTMPolicy := getNewTopologyManagerPolicyValue (initialTMPolicy )
319+ Expect (initialTMPolicy ).ToNot (Equal (newTMPolicy ), "new TM policy should differ from the initial one" )
320+
321+ By ("retrieving the PerformanceProfile configmap from the management cluster" )
322+ hostedClusterName , err := hypershift .GetHostedClusterName ()
323+ Expect (err ).ToNot (HaveOccurred ())
324+ nodePool , err := nodepools .GetByClusterName (context .TODO (), e2eclient .MNGClient , hostedClusterName )
325+ Expect (err ).ToNot (HaveOccurred ())
326+
327+ By ("validating the tuningConfig name against ConfigMaps in the management cluster" )
328+ tuningConfigName := nodePool .Spec .TuningConfig [0 ].Name
329+ Expect (tuningConfigName ).ToNot (BeEmpty (), "NodePool tuningConfig name is empty" )
330+
331+ cmList := & corev1.ConfigMapList {}
332+ err = e2eclient .MNGClient .List (context .TODO (), cmList , & client.ListOptions {
333+ Namespace : "clusters" ,
334+ })
335+ Expect (err ).ToNot (HaveOccurred (), "failed to list ConfigMaps in namespace: clusters" )
336+
337+ var targetCM * corev1.ConfigMap
338+ for i := range cmList .Items {
339+ if cmList .Items [i ].Name == tuningConfigName {
340+ targetCM = & cmList .Items [i ]
341+ break
342+ }
343+ }
344+ Expect (targetCM ).ToNot (BeNil (), fmt .Sprintf ("ConfigMap %q not found in namespace: clusters" , tuningConfigName ))
345+
346+ By ("updating the ConfigMap with the new TM policy" )
347+ yamlData := targetCM .Data ["tuning" ]
348+ Expect (yamlData ).ToNot (BeEmpty (), "tuning section not found in ConfigMap" )
349+
350+ var tuning Tuning
351+ err = yaml .Unmarshal ([]byte (yamlData ), & tuning )
352+ Expect (err ).ToNot (HaveOccurred (), "failed to unmarshal ConfigMap tuning YAML" )
353+ Expect (tuning .Profile .CPU .TopologyManagerPolicy ).To (Equal (initialTMPolicy ), "unexpected initial TM policy in parsed YAML" )
354+
355+ tuning .Profile .CPU .TopologyManagerPolicy = newTMPolicy
356+
357+ modifiedYamlBytes , err := yaml .Marshal (& tuning )
358+ Expect (err ).ToNot (HaveOccurred (), "failed to marshal modified tuning YAML" )
359+ modifiedYaml := string (modifiedYamlBytes )
360+ Expect (modifiedYaml ).ToNot (Equal (yamlData ), "no changes applied to ConfigMap YAML" )
361+
362+ targetCM .Data ["tuning" ] = modifiedYaml
363+ err = e2eclient .MNGClient .Update (context .TODO (), targetCM )
364+ Expect (err ).ToNot (HaveOccurred (), "failed to update the ConfigMap with new TM policy" )
365+
366+ By ("waiting for the NRT to reflect the new TM policy" )
367+ Eventually (func (g Gomega ) {
368+ updatedNrtList := nrtv1alpha2.NodeResourceTopologyList {}
369+ updatedNrtList , err = e2enrt .GetUpdated (fxt .Client , updatedNrtList , timeout )
370+ g .Expect (err ).ToNot (HaveOccurred ())
371+ g .Expect (updatedNrtList .Items ).ToNot (BeEmpty ())
372+
373+ var updatedTM string
374+ for _ , attr := range updatedNrtList .Items [0 ].Attributes {
375+ if attr .Name == "topologyManagerPolicy" {
376+ updatedTM = attr .Value
377+ break
378+ }
379+ }
380+ g .Expect (updatedTM ).To (Equal (newTMPolicy ), "Expected updated TM policy %q, but got %q" , newTMPolicy , updatedTM )
381+ }, 10 * time .Minute , 25 * time .Second ).Should (Succeed (), "NRT did not reflect updated TM policy in time" )
382+ })
383+
288384 It ("should report the NodeGroupConfig in the status" , Label ("tier2" , "openshift" ), func () {
289385 nroKey := objects .NROObjectKey ()
290386 nroOperObj := nropv1.NUMAResourcesOperator {}
@@ -732,6 +828,14 @@ func objRefListToStringList(objRefs []configv1.ObjectReference) []string {
732828 return ret
733829}
734830
831+ func getNewTopologyManagerPolicyValue (oldTopologyManagerPolicyValue string ) string {
832+ newTopologyManagerPolicyValue := "best-effort"
833+ if oldTopologyManagerPolicyValue == newTopologyManagerPolicyValue || oldTopologyManagerPolicyValue == "" {
834+ newTopologyManagerPolicyValue = "single-numa-node"
835+ }
836+ return newTopologyManagerPolicyValue
837+ }
838+
735839func toJSON (obj interface {}) string {
736840 data , err := json .Marshal (obj )
737841 if err != nil {
0 commit comments