mirror of
https://github.com/open-cluster-management-io/ocm.git
synced 2026-08-23 22:26:49 +00:00
* Move addon api to beta in registration Signed-off-by: Jian Qiu <jqiu@redhat.com> * Update conversion e2e tests Signed-off-by: Jian Qiu <jqiu@redhat.com> * Add addon v1beta1 to supported type in grpc Signed-off-by: Jian Qiu <jqiu@redhat.com> * Fix flaky e2e in addon conversion Signed-off-by: Jian Qiu <jqiu@redhat.com> * Set subject for registration configuration when it is not set Signed-off-by: Jian Qiu <jqiu@redhat.com> --------- Signed-off-by: Jian Qiu <jqiu@redhat.com>
155 lines
5.0 KiB
Go
155 lines
5.0 KiB
Go
package addon
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/openshift/library-go/pkg/operator/resource/resourcemerge"
|
|
"k8s.io/apimachinery/pkg/api/errors"
|
|
"k8s.io/apimachinery/pkg/api/meta"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
|
|
addonv1beta1 "open-cluster-management.io/api/addon/v1beta1"
|
|
addoninformerv1beta1 "open-cluster-management.io/api/client/addon/informers/externalversions/addon/v1beta1"
|
|
addonlisterv1beta1 "open-cluster-management.io/api/client/addon/listers/addon/v1beta1"
|
|
clientset "open-cluster-management.io/api/client/cluster/clientset/versioned"
|
|
clusterv1informer "open-cluster-management.io/api/client/cluster/informers/externalversions/cluster/v1"
|
|
clusterv1listers "open-cluster-management.io/api/client/cluster/listers/cluster/v1"
|
|
clusterv1 "open-cluster-management.io/api/cluster/v1"
|
|
"open-cluster-management.io/sdk-go/pkg/basecontroller/factory"
|
|
"open-cluster-management.io/sdk-go/pkg/patcher"
|
|
|
|
"open-cluster-management.io/ocm/pkg/common/queue"
|
|
)
|
|
|
|
const (
|
|
addOnFeaturePrefix = "feature.open-cluster-management.io/addon-"
|
|
addOnStatusAvailable = "available"
|
|
addOnStatusUnhealthy = "unhealthy"
|
|
addOnStatusUnreachable = "unreachable"
|
|
)
|
|
|
|
// addOnFeatureDiscoveryController monitors ManagedCluster and its ManagedClusterAddOns on hub and
|
|
// create/update/delete labels of the ManagedCluster to reflect the status of addons.
|
|
type addOnFeatureDiscoveryController struct {
|
|
patcher patcher.Patcher[*clusterv1.ManagedCluster, clusterv1.ManagedClusterSpec, clusterv1.ManagedClusterStatus]
|
|
clusterLister clusterv1listers.ManagedClusterLister
|
|
addOnLister addonlisterv1beta1.ManagedClusterAddOnLister
|
|
}
|
|
|
|
// NewAddOnFeatureDiscoveryController returns an instance of addOnFeatureDiscoveryController
|
|
func NewAddOnFeatureDiscoveryController(
|
|
clusterClient clientset.Interface,
|
|
clusterInformer clusterv1informer.ManagedClusterInformer,
|
|
addOnInformers addoninformerv1beta1.ManagedClusterAddOnInformer,
|
|
) factory.Controller {
|
|
c := &addOnFeatureDiscoveryController{
|
|
patcher: patcher.NewPatcher[
|
|
*clusterv1.ManagedCluster, clusterv1.ManagedClusterSpec, clusterv1.ManagedClusterStatus](
|
|
clusterClient.ClusterV1().ManagedClusters()),
|
|
clusterLister: clusterInformer.Lister(),
|
|
addOnLister: addOnInformers.Lister(),
|
|
}
|
|
|
|
return factory.New().
|
|
WithInformersQueueKeysFunc(
|
|
queue.QueueKeyByMetaName,
|
|
clusterInformer.Informer()).
|
|
WithInformersQueueKeysFunc(
|
|
queue.QueueKeyByMetaNamespace,
|
|
addOnInformers.Informer()).
|
|
WithSync(c.sync).
|
|
ToController("AddOnFeatureDiscoveryController")
|
|
}
|
|
|
|
func (c *addOnFeatureDiscoveryController) sync(ctx context.Context, syncCtx factory.SyncContext, queueKey string) error {
|
|
switch {
|
|
case queueKey == factory.DefaultQueueKey:
|
|
// no need to resync
|
|
return nil
|
|
default:
|
|
// sync the cluster
|
|
return c.syncCluster(ctx, queueKey)
|
|
}
|
|
}
|
|
|
|
func (c *addOnFeatureDiscoveryController) syncCluster(ctx context.Context, clusterName string) error {
|
|
// sync all addon labels on the managed cluster
|
|
cluster, err := c.clusterLister.Get(clusterName)
|
|
if errors.IsNotFound(err) {
|
|
// cluster is deleted
|
|
return nil
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Do not update addon label if cluster is deleting
|
|
if !cluster.DeletionTimestamp.IsZero() {
|
|
return nil
|
|
}
|
|
|
|
// Do not update if cluster has no available condition yet.
|
|
if meta.FindStatusCondition(cluster.Status.Conditions, clusterv1.ManagedClusterConditionAvailable) == nil {
|
|
return nil
|
|
}
|
|
|
|
// build labels for existing addons
|
|
addOnLabels := map[string]string{}
|
|
addOns, err := c.addOnLister.ManagedClusterAddOns(clusterName).List(labels.Everything())
|
|
if err != nil {
|
|
return fmt.Errorf("unable to list addOns of cluster %q: %w", clusterName, err)
|
|
}
|
|
for _, addOn := range addOns {
|
|
// addon is deleting
|
|
if !addOn.DeletionTimestamp.IsZero() {
|
|
continue
|
|
}
|
|
key := fmt.Sprintf("%s%s", addOnFeaturePrefix, addOn.Name)
|
|
addOnLabels[key] = getAddOnLabelValue(addOn)
|
|
}
|
|
|
|
// remove addon lable if its corresponding addon no longer exists
|
|
for key := range cluster.Labels {
|
|
if !strings.HasPrefix(key, addOnFeaturePrefix) {
|
|
continue
|
|
}
|
|
|
|
if _, ok := addOnLabels[key]; !ok {
|
|
addOnLabels[fmt.Sprintf("%s-", key)] = ""
|
|
}
|
|
}
|
|
|
|
// merge labels
|
|
modified := false
|
|
newCluster := cluster.DeepCopy()
|
|
resourcemerge.MergeMap(&modified, &newCluster.Labels, addOnLabels)
|
|
|
|
// no work if the cluster labels have no change
|
|
if !modified {
|
|
return nil
|
|
}
|
|
|
|
// otherwise, update cluster
|
|
_, err = c.patcher.PatchLabelAnnotations(ctx, newCluster, newCluster.ObjectMeta, cluster.ObjectMeta)
|
|
return err
|
|
}
|
|
|
|
func getAddOnLabelValue(addOn *addonv1beta1.ManagedClusterAddOn) string {
|
|
availableCondition := meta.FindStatusCondition(addOn.Status.Conditions, addonv1beta1.ManagedClusterAddOnConditionAvailable)
|
|
if availableCondition == nil {
|
|
return addOnStatusUnreachable
|
|
}
|
|
|
|
switch availableCondition.Status {
|
|
case metav1.ConditionTrue:
|
|
return addOnStatusAvailable
|
|
case metav1.ConditionFalse:
|
|
return addOnStatusUnhealthy
|
|
default:
|
|
return addOnStatusUnreachable
|
|
}
|
|
}
|