@@ -2,6 +2,7 @@ package proposal
22
33import (
44 "context"
5+ "encoding/json"
56 "fmt"
67 "os"
78 "regexp"
@@ -17,20 +18,23 @@ import (
1718 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1819 kutilerrors "k8s.io/apimachinery/pkg/util/errors"
1920 "k8s.io/apimachinery/pkg/util/sets"
21+ "k8s.io/client-go/dynamic"
2022 "k8s.io/client-go/util/workqueue"
2123 "k8s.io/klog/v2"
2224
2325 configv1 "github.com/openshift/api/config/v1"
2426 proposalv1alpha1 "github.com/openshift/lightspeed-agentic-operator/api/v1alpha1"
2527
2628 i "github.com/openshift/cluster-version-operator/pkg/internal"
29+ "github.com/openshift/cluster-version-operator/pkg/readiness"
2730)
2831
2932type Controller struct {
3033 queueKey string
3134 queue workqueue.TypedRateLimitingInterface [any ]
3235 updatesGetterFunc updatesGetterFunc
3336 client ctrlruntimeclient.Client
37+ dynamicClient dynamic.Interface
3438 cvGetterFunc cvGetterFunc
3539 configMapGetterFunc configMapGetterFunc
3640 getCurrentVersionFunc getCurrentVersionFunc
@@ -57,6 +61,7 @@ type configMapGetterFunc func(ctx context.Context, namespace, name string, opts
5761func NewController (
5862 updatesGetterFunc updatesGetterFunc ,
5963 client ctrlruntimeclient.Client ,
64+ dynamicClient dynamic.Interface ,
6065 cvGetterFunc cvGetterFunc ,
6166 configMapGetterFunc configMapGetterFunc ,
6267 getCurrentVersionFunc getCurrentVersionFunc ,
@@ -68,6 +73,7 @@ func NewController(
6873 workqueue.TypedRateLimitingQueueConfig [any ]{Name : controllerName }),
6974 updatesGetterFunc : updatesGetterFunc ,
7075 client : client ,
76+ dynamicClient : dynamicClient ,
7177 cvGetterFunc : cvGetterFunc ,
7278 configMapGetterFunc : configMapGetterFunc ,
7379 getCurrentVersionFunc : getCurrentVersionFunc ,
@@ -152,9 +158,7 @@ func (c *Controller) Sync(ctx context.Context, key string) error {
152158 return kutilerrors .NewAggregate (errs )
153159 }
154160
155- // TODO: Implement it
156- readinessJSON := "{}"
157- proposals , err := getProposals (updates , conditionalUpdates , c .config .Namespace , currentVersion , cv .Spec .Channel , prompt , readinessJSON )
161+ proposals , err := getProposals (ctx , c .dynamicClient , updates , conditionalUpdates , c .config .Namespace , currentVersion , cv .Spec .Channel , prompt )
158162 if err != nil {
159163 klog .V (i .Normal ).Infof ("Getting proposals hit an error: %v" , err )
160164 return kutilerrors .NewAggregate (append (errs , err ))
@@ -277,17 +281,23 @@ func deleteProposal(ctx context.Context, client ctrlruntimeclient.Client, propos
277281}
278282
279283func getProposals (
284+ ctx context.Context ,
285+ dynamicClient dynamic.Interface ,
280286 availableUpdates []configv1.Release ,
281287 conditionalUpdates []configv1.ConditionalUpdate ,
282288 namespace string ,
283289 currentVersion , channel ,
284290 systemPrompt string ,
285- readinessJSON string ,
286291) ([]* proposalv1alpha1.Proposal , error ) {
292+ // TODO: Only 2 of 9 readiness checks (api_deprecations, olm_lifecycle) use the target version.
293+ // The other 7 query cluster-wide state identical across targets. For clusters with many available
294+ // updates, split into target-independent checks (run once) and target-dependent checks (run per
295+ // target) to reduce redundant API calls.
287296 var errs []error
288297 var proposals []* proposalv1alpha1.Proposal
289298 for _ , au := range availableUpdates {
290299 targetVersion := au .Version
300+ readinessJSON := runReadinessJSON (ctx , dynamicClient , currentVersion , targetVersion )
291301 if proposal , err := getProposal (namespace , currentVersion , targetVersion , channel , updateKindRecommended , systemPrompt , readinessJSON , availableUpdates ); err != nil {
292302 errs = append (errs , err )
293303 continue
@@ -298,6 +308,7 @@ func getProposals(
298308
299309 for _ , cu := range conditionalUpdates {
300310 targetVersion := cu .Release .Version
311+ readinessJSON := runReadinessJSON (ctx , dynamicClient , currentVersion , targetVersion )
301312 if proposal , err := getProposal (namespace , currentVersion , targetVersion , channel , updateKindConditional , systemPrompt , readinessJSON , availableUpdates ); err != nil {
302313 errs = append (errs , err )
303314 continue
@@ -437,6 +448,20 @@ func classifyUpdate(current, target string) string {
437448 return i .UpdateType (cv , tv )
438449}
439450
451+ func runReadinessJSON (ctx context.Context , dynamicClient dynamic.Interface , currentVersion , targetVersion string ) string {
452+ if dynamicClient == nil {
453+ klog .V (i .Normal ).Infof ("Dynamic client is nil; skipping readiness checks for %s -> %s" , currentVersion , targetVersion )
454+ return "{}"
455+ }
456+ output := readiness .RunAll (ctx , dynamicClient , currentVersion , targetVersion )
457+ data , err := json .Marshal (output )
458+ if err != nil {
459+ klog .V (i .Normal ).Infof ("Failed to marshal readiness output for %s -> %s: %v" , currentVersion , targetVersion , err )
460+ return "{}"
461+ }
462+ return string (data )
463+ }
464+
440465// buildRequest constructs the proposal request with system prompt, metadata, and readiness data.
441466func buildRequest (systemPrompt , current , target , channel , updateType , targetType string ,
442467 updates []configv1.Release , readinessJSON string ) string {
0 commit comments