@@ -15,7 +15,7 @@ limitations under the License.
1515
1616Based on code from https://github.com/yevgeny-shnaidman/amd-gpu-operator
1717
18- Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
18+ Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
1919SPDX-License-Identifier: BSD-3-Clause-Clear
2020Not a contribution.
2121*/
@@ -28,6 +28,7 @@ import (
2828 "fmt"
2929
3030 kmmv1beta1 "github.com/rh-ecosystem-edge/kernel-module-management/api/v1beta1"
31+ nfr "github.com/openshift/cluster-nfd-operator/api/v1alpha1"
3132 v1 "k8s.io/api/core/v1"
3233 k8serrors "k8s.io/apimachinery/pkg/api/errors"
3334 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -40,6 +41,7 @@ import (
4041
4142 aicv1 "github.com/quic/aic-operator/api/v1"
4243 "github.com/quic/aic-operator/internal/kmmmodule"
44+ "github.com/quic/aic-operator/internal/nfdrule"
4345)
4446
4547// AICReconciler reconciles an AIC object
@@ -54,6 +56,8 @@ type AICReconciler struct {
5456//+kubebuilder:rbac:groups=aic.quicinc.com,resources=aics/finalizers,verbs=update
5557//+kubebuilder:rbac:groups=kmm.sigs.x-k8s.io,resources=modules,verbs=get;list;watch;create;patch;update;delete
5658//+kubebuilder:rbac:groups=kmm.sigs.x-k8s.io,resources=modules/status,verbs=get;update;patch
59+ //+kubebuilder:rbac:groups=nfd.openshift.io,resources=nodefeaturerules,verbs=get;list;watch;create;update;patch;delete
60+ //+kubebuilder:rbac:groups=nfd.openshift.io,resources=nodefeaturerules/status,verbs=get;update;patch
5761//+kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterroles;clusterrolebindings;roles;rolebindings,verbs=get;list;watch;create;update;patch;delete
5862//+kubebuilder:rbac:groups=core,resources=namespaces;serviceaccounts;pods;pods/exec;pods/attach;services;services/finalizers;endpoints,verbs=get;list;watch;create;update;patch;delete
5963//+kubebuilder:rbac:groups=core,resources=configmaps;secrets;nodes,verbs=get;list;watch;create;update;patch;delete
@@ -63,8 +67,9 @@ type AICReconciler struct {
6367func NewAICReconciler (
6468 client client.Client ,
6569 scheme * runtime.Scheme ,
66- kmmHandler kmmmodule.KMMModuleAPI ) * AICReconciler {
67- helper := newAICReconcilerHelper (client , kmmHandler )
70+ kmmHandler kmmmodule.KMMModuleAPI ,
71+ nfdHandler nfdrule.NFDRuleAPI ) * AICReconciler {
72+ helper := newAICReconcilerHelper (client , kmmHandler , nfdHandler )
6873 return & AICReconciler {
6974 Client : client ,
7075 Scheme : scheme ,
@@ -114,6 +119,12 @@ func (r *AICReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R
114119 return res , fmt .Errorf ("failed to set finalizer for AIC %s: %v" , req .NamespacedName , err )
115120 }
116121
122+ logger .Info ("start NFR reconciliation" )
123+ err = r .helper .handleAICNFDRule (ctx , aic )
124+ if err != nil {
125+ return res , fmt .Errorf ("failed to handle NFR creation %s: %v" , req .NamespacedName , err )
126+ }
127+
117128 logger .Info ("start build configmap reconciliation" )
118129 // Always want to have the ConfigMap that can build module images
119130 err = r .helper .handleBuildConfigMap (ctx , aic , false )
@@ -156,18 +167,21 @@ type AICReconcilerHelperAPI interface {
156167 setFinalizer (ctx context.Context , aic * aicv1.AIC ) error
157168 handleBuildConfigMap (ctx context.Context , devConfig * aicv1.AIC , useInTree bool ) error
158169 handleKMMModule (ctx context.Context , devConfig * aicv1.AIC , loadedMods aicv1.LoadedModules ) error
170+ handleAICNFDRule (ctx context.Context , aic * aicv1.AIC ) error
159171}
160172
161173type AICReconcilerHelper struct {
162174 client client.Client
163175 kmmHandler kmmmodule.KMMModuleAPI
176+ nfdHandler nfdrule.NFDRuleAPI
164177}
165178
166179func newAICReconcilerHelper (client client.Client ,
167- kmmHandler kmmmodule.KMMModuleAPI ) AICReconcilerHelperAPI {
180+ kmmHandler kmmmodule.KMMModuleAPI , nfdHandler nfdrule. NFDRuleAPI ) AICReconcilerHelperAPI {
168181 return & AICReconcilerHelper {
169182 client : client ,
170183 kmmHandler : kmmHandler ,
184+ nfdHandler : nfdHandler ,
171185 }
172186}
173187func (aicrh * AICReconcilerHelper ) getRequestedAIC (ctx context.Context , namespacedName types.NamespacedName ) (* aicv1.AIC , error ) {
@@ -215,12 +229,31 @@ func (aicrh *AICReconcilerHelper) finalizeAIC(ctx context.Context, aic *aicv1.AI
215229 faults = append (faults , err )
216230 }
217231 }
232+ //Delete NFR owned by AIC.
233+ nfrObj := nfr.NodeFeatureRule {}
234+ nsName := types.NamespacedName {
235+ Namespace : aic .Namespace ,
236+ Name : "qcom-aic-nfr" ,
237+ }
238+ err = aicrh .client .Get (ctx , nsName , & nfrObj )
239+ if err != nil {
240+ if k8serrors .IsNotFound (err ) {
241+ deleted = append (deleted , err )
242+ } else {
243+ faults = append (faults , fmt .Errorf ("failed to get the requested NFR %s: %w" , nsName , err ))
244+ }
245+ } else {
246+ logger .Info ("deleting NFR CR" , "NFR" , nsName )
247+ if err = aicrh .client .Delete (ctx , & nfrObj ); client .IgnoreNotFound (err ) != nil {
248+ faults = append (faults , err )
249+ }
250+ }
218251
219252 err = errors .Join (faults ... )
220253
221254 //remove finalizer only if no faults occurred during removal
222- if len (deleted ) == int (aicv1 .None_loaded )+ 1 && err == nil {
223- logger .Info ("modules already deleted, removing finalizer" , "module" , aic .Name )
255+ if len (deleted ) == int (aicv1 .None_loaded )+ 2 && err == nil {
256+ logger .Info ("modules & NFR already deleted, removing finalizer" , "module, NFR " , aic .Name )
224257 aicCopy := aic .DeepCopy ()
225258 controllerutil .RemoveFinalizer (aic , aicFinalizer )
226259 return aicrh .client .Patch (ctx , aic , client .MergeFrom (aicCopy ))
@@ -271,6 +304,25 @@ func (aicrh *AICReconcilerHelper) handleKMMModule(ctx context.Context, aic *aicv
271304 return err
272305}
273306
307+ func (aicrh * AICReconcilerHelper ) handleAICNFDRule (ctx context.Context , aic * aicv1.AIC ) error {
308+
309+ nfrObj := & nfr.NodeFeatureRule {
310+ ObjectMeta : metav1.ObjectMeta {
311+ Namespace : aic .Namespace ,
312+ Name : "qcom-aic-nfr" ,
313+ },
314+ }
315+ logger := log .FromContext (ctx )
316+ opRes , err := controllerutil .CreateOrPatch (ctx , aicrh .client , nfrObj , func () error {
317+ return aicrh .nfdHandler .SetNFRasDesired (nfrObj , aic )
318+ })
319+ if err != nil {
320+ logger .Info ("Reconciled NFR" , "name" , nfrObj .Name , "result" , opRes )
321+ return err
322+ }
323+ return nil
324+
325+ }
274326func getDockerfileCMName (aic * aicv1.AIC , useInTree bool ) string {
275327 if useInTree {
276328 return "dockerfile-intree-" + aic .Name
0 commit comments