Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,95 @@
"source": "openshift:payload:cluster-version-operator",
"lifecycle": "informing",
"environmentSelector": {}
},
{
"name": "[Jira:\"Cluster Version Operator\"] cluster-version-operator readiness checks should run all checks without errors",
"labels": {},
"resources": {
"isolation": {}
},
"source": "openshift:payload:cluster-version-operator",
"lifecycle": "blocking",
"environmentSelector": {}
},
{
"name": "[Jira:\"Cluster Version Operator\"] cluster-version-operator readiness checks should produce valid JSON that round-trips",
"labels": {},
"resources": {
"isolation": {}
},
"source": "openshift:payload:cluster-version-operator",
"lifecycle": "blocking",
"environmentSelector": {}
},
{
"name": "[Jira:\"Cluster Version Operator\"] cluster-version-operator readiness checks should report node count matching the actual cluster",
"labels": {},
"resources": {
"isolation": {}
},
"source": "openshift:payload:cluster-version-operator",
"lifecycle": "blocking",
"environmentSelector": {}
},
{
"name": "[Jira:\"Cluster Version Operator\"] cluster-version-operator readiness checks should report operator count matching actual ClusterOperators",
"labels": {},
"resources": {
"isolation": {}
},
"source": "openshift:payload:cluster-version-operator",
"lifecycle": "blocking",
"environmentSelector": {}
},
{
"name": "[Jira:\"Cluster Version Operator\"] cluster-version-operator readiness checks should report etcd member count matching actual etcd pods",
"labels": {},
"resources": {
"isolation": {}
},
"source": "openshift:payload:cluster-version-operator",
"lifecycle": "blocking",
"environmentSelector": {}
},
{
"name": "[Jira:\"Cluster Version Operator\"] cluster-version-operator readiness checks should report network type matching actual Network config",
"labels": {},
"resources": {
"isolation": {}
},
"source": "openshift:payload:cluster-version-operator",
"lifecycle": "blocking",
"environmentSelector": {}
},
{
"name": "[Jira:\"Cluster Version Operator\"] cluster-version-operator readiness checks should report PDB count matching actual PodDisruptionBudgets",
"labels": {},
"resources": {
"isolation": {}
},
"source": "openshift:payload:cluster-version-operator",
"lifecycle": "blocking",
"environmentSelector": {}
},
{
"name": "[Jira:\"Cluster Version Operator\"] cluster-version-operator readiness checks should report cluster conditions matching ClusterVersion status",
"labels": {},
"resources": {
"isolation": {}
},
"source": "openshift:payload:cluster-version-operator",
"lifecycle": "blocking",
"environmentSelector": {}
},
{
"name": "[Jira:\"Cluster Version Operator\"] cluster-version-operator readiness checks should complete all checks within 60 seconds",
"labels": {},
"resources": {
"isolation": {}
},
"source": "openshift:payload:cluster-version-operator",
"lifecycle": "blocking",
"environmentSelector": {}
}
]
2 changes: 1 addition & 1 deletion pkg/cvo/availableupdates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ func newOperator(url string, cluster release, promqlMock clusterconditions.Condi
func() ([]configv1.Release, []configv1.ConditionalUpdate, error) {
return nil, nil, nil
},
fake.NewClientBuilder().Build(), func(_ string) (*configv1.ClusterVersion, error) {
fake.NewClientBuilder().Build(), nil, func(_ string) (*configv1.ClusterVersion, error) {
return &configv1.ClusterVersion{}, nil
},
func(_ context.Context, namespace, name string, _ metav1.GetOptions) (*corev1.ConfigMap, error) {
Expand Down
5 changes: 5 additions & 0 deletions pkg/cvo/cvo.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/dynamic"
informerscorev1 "k8s.io/client-go/informers/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
Expand Down Expand Up @@ -109,6 +110,7 @@ type Operator struct {

client clientset.Interface
kubeClient kubernetes.Interface
dynamicClient dynamic.Interface
operatorClient operatorclientset.Interface
eventRecorder record.EventRecorder

Expand Down Expand Up @@ -235,6 +237,7 @@ func New(
featureGateInformer configinformersv1.FeatureGateInformer,
client clientset.Interface,
kubeClient kubernetes.Interface,
dynamicClient dynamic.Interface,
operatorClient operatorclientset.Interface,
exclude string,
clusterProfile string,
Expand Down Expand Up @@ -267,6 +270,7 @@ func New(

client: client,
kubeClient: kubeClient,
dynamicClient: dynamicClient,
operatorClient: operatorClient,
eventRecorder: eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: namespace}),
queue: workqueue.NewTypedRateLimitingQueueWithConfig(workqueue.DefaultTypedControllerRateLimiter[any](), workqueue.TypedRateLimitingQueueConfig[any]{Name: "clusterversion"}),
Expand Down Expand Up @@ -354,6 +358,7 @@ func New(
return availableUpdates.Updates, availableUpdates.ConditionalUpdates, nil
},
rtClient,
dynamicClient,
cvInformer.Lister().Get,
func(ctx context.Context, namespace, name string, opts metav1.GetOptions) (*corev1.ConfigMap, error) {
return kubeClient.CoreV1().ConfigMaps(namespace).Get(ctx, name, opts)
Expand Down
2 changes: 1 addition & 1 deletion pkg/cvo/cvo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2756,7 +2756,7 @@ func TestOperator_availableUpdatesSync(t *testing.T) {
ctx := context.Background()
optr.proposalController = proposal.NewController(func() ([]configv1.Release, []configv1.ConditionalUpdate, error) {
return nil, nil, nil
}, ctrlruntimefake.NewClientBuilder().Build(), func(_ string) (*configv1.ClusterVersion, error) {
}, ctrlruntimefake.NewClientBuilder().Build(), nil, func(_ string) (*configv1.ClusterVersion, error) {
return &configv1.ClusterVersion{}, nil
}, func(_ context.Context, namespace, name string, _ metav1.GetOptions) (*corev1.ConfigMap, error) {
return &corev1.ConfigMap{}, nil
Expand Down
33 changes: 29 additions & 4 deletions pkg/proposal/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package proposal

import (
"context"
"encoding/json"
"fmt"
"os"
"regexp"
Expand All @@ -17,20 +18,23 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kutilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/util/workqueue"
"k8s.io/klog/v2"

configv1 "github.com/openshift/api/config/v1"
proposalv1alpha1 "github.com/openshift/lightspeed-agentic-operator/api/v1alpha1"

i "github.com/openshift/cluster-version-operator/pkg/internal"
"github.com/openshift/cluster-version-operator/pkg/readiness"
)

type Controller struct {
queueKey string
queue workqueue.TypedRateLimitingInterface[any]
updatesGetterFunc updatesGetterFunc
client ctrlruntimeclient.Client
dynamicClient dynamic.Interface
cvGetterFunc cvGetterFunc
configMapGetterFunc configMapGetterFunc
getCurrentVersionFunc getCurrentVersionFunc
Expand All @@ -57,6 +61,7 @@ type configMapGetterFunc func(ctx context.Context, namespace, name string, opts
func NewController(
updatesGetterFunc updatesGetterFunc,
client ctrlruntimeclient.Client,
dynamicClient dynamic.Interface,
cvGetterFunc cvGetterFunc,
configMapGetterFunc configMapGetterFunc,
getCurrentVersionFunc getCurrentVersionFunc,
Expand All @@ -68,6 +73,7 @@ func NewController(
workqueue.TypedRateLimitingQueueConfig[any]{Name: controllerName}),
updatesGetterFunc: updatesGetterFunc,
client: client,
dynamicClient: dynamicClient,
cvGetterFunc: cvGetterFunc,
configMapGetterFunc: configMapGetterFunc,
getCurrentVersionFunc: getCurrentVersionFunc,
Expand Down Expand Up @@ -152,9 +158,7 @@ func (c *Controller) Sync(ctx context.Context, key string) error {
return kutilerrors.NewAggregate(errs)
}

// TODO: Implement it
readinessJSON := "{}"
proposals, err := getProposals(updates, conditionalUpdates, c.config.Namespace, currentVersion, cv.Spec.Channel, prompt, readinessJSON)
proposals, err := getProposals(ctx, c.dynamicClient, updates, conditionalUpdates, c.config.Namespace, currentVersion, cv.Spec.Channel, prompt)
if err != nil {
klog.V(i.Normal).Infof("Getting proposals hit an error: %v", err)
return kutilerrors.NewAggregate(append(errs, err))
Expand Down Expand Up @@ -277,17 +281,23 @@ func deleteProposal(ctx context.Context, client ctrlruntimeclient.Client, propos
}

func getProposals(
ctx context.Context,
dynamicClient dynamic.Interface,
availableUpdates []configv1.Release,
conditionalUpdates []configv1.ConditionalUpdate,
namespace string,
currentVersion, channel,
systemPrompt string,
readinessJSON string,
) ([]*proposalv1alpha1.Proposal, error) {
// TODO: Only 2 of 9 readiness checks (api_deprecations, olm_lifecycle) use the target version.
// The other 7 query cluster-wide state identical across targets. For clusters with many available
// updates, split into target-independent checks (run once) and target-dependent checks (run per
// target) to reduce redundant API calls.
var errs []error
var proposals []*proposalv1alpha1.Proposal
for _, au := range availableUpdates {
targetVersion := au.Version
readinessJSON := runReadinessJSON(ctx, dynamicClient, currentVersion, targetVersion)
if proposal, err := getProposal(namespace, currentVersion, targetVersion, channel, updateKindRecommended, systemPrompt, readinessJSON, availableUpdates); err != nil {
errs = append(errs, err)
continue
Expand All @@ -298,6 +308,7 @@ func getProposals(

for _, cu := range conditionalUpdates {
targetVersion := cu.Release.Version
readinessJSON := runReadinessJSON(ctx, dynamicClient, currentVersion, targetVersion)
if proposal, err := getProposal(namespace, currentVersion, targetVersion, channel, updateKindConditional, systemPrompt, readinessJSON, availableUpdates); err != nil {
errs = append(errs, err)
continue
Expand Down Expand Up @@ -437,6 +448,20 @@ func classifyUpdate(current, target string) string {
return i.UpdateType(cv, tv)
}

func runReadinessJSON(ctx context.Context, dynamicClient dynamic.Interface, currentVersion, targetVersion string) string {
if dynamicClient == nil {
klog.V(i.Normal).Infof("Dynamic client is nil; skipping readiness checks for %s -> %s", currentVersion, targetVersion)
return "{}"
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
output := readiness.RunAll(ctx, dynamicClient, currentVersion, targetVersion)
data, err := json.Marshal(output)
if err != nil {
klog.V(i.Normal).Infof("Failed to marshal readiness output for %s -> %s: %v", currentVersion, targetVersion, err)
return "{}"
}
return string(data)
}

// buildRequest constructs the proposal request with system prompt, metadata, and readiness data.
func buildRequest(systemPrompt, current, target, channel, updateType, targetType string,
updates []configv1.Release, readinessJSON string) string {
Expand Down
Loading