mirror of
https://github.com/open-cluster-management-io/ocm.git
synced 2026-08-23 22:26:49 +00:00
152 lines
5.8 KiB
Go
152 lines
5.8 KiB
Go
package addonconfiguration
|
|
|
|
import (
|
|
"context"
|
|
|
|
"k8s.io/apimachinery/pkg/api/meta"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
|
"k8s.io/apimachinery/pkg/util/sets"
|
|
|
|
addonv1beta1 "open-cluster-management.io/api/addon/v1beta1"
|
|
addonclient "open-cluster-management.io/api/client/addon/clientset/versioned"
|
|
"open-cluster-management.io/sdk-go/pkg/patcher"
|
|
|
|
"open-cluster-management.io/ocm/pkg/common/helpers"
|
|
)
|
|
|
|
type managedClusterAddonConfigurationReconciler struct {
|
|
addonClient addonclient.Interface
|
|
}
|
|
|
|
func (d *managedClusterAddonConfigurationReconciler) reconcile(
|
|
ctx context.Context, cma *addonv1beta1.ClusterManagementAddOn, graph *configurationGraph) (*addonv1beta1.ClusterManagementAddOn, reconcileState, error) {
|
|
var errs []error
|
|
configured := sets.Set[string]{}
|
|
|
|
// Update the config references and set the "configured" condition to true for addons that are ready for rollout.
|
|
// These addons are part of the current rollout batch according to the strategy.
|
|
for _, addon := range graph.getAddonsToUpdate() {
|
|
// update mca config references in status
|
|
newAddon := d.mergeAddonConfig(addon.mca, addon.desiredConfigs)
|
|
// update mca configured condition to true
|
|
d.setCondition(newAddon, metav1.ConditionTrue, "ConfigurationsConfigured", "Configurations configured")
|
|
|
|
err := d.patchAddonStatus(ctx, newAddon, addon.mca)
|
|
if err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
|
|
configured.Insert(addon.mca.Namespace)
|
|
}
|
|
|
|
// Set the "configured" condition to false for addons whose configurations have not been synced yet
|
|
// but are waiting for rollout.
|
|
for _, addon := range graph.getAddonsToApply() {
|
|
// Skip addons that have already been configured.
|
|
if configured.Has(addon.mca.Namespace) {
|
|
continue
|
|
}
|
|
newAddon := addon.mca.DeepCopy()
|
|
d.setCondition(newAddon, metav1.ConditionFalse, "ConfigurationsNotConfigured", "Configurations updated and not configured yet")
|
|
|
|
err := d.patchAddonStatus(ctx, newAddon, addon.mca)
|
|
if err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
|
|
// Set the "configured" condition to true for addons that have successfully completed rollout.
|
|
// This includes:
|
|
// a. Addons without any configurations that have had their rollout status set to success in setRolloutStatus().
|
|
// b. Addons with configurations and already rollout successfully. In upgrade scenario, when the
|
|
// addon configurations do not change while addon components upgrade, should set condition to true.
|
|
for _, addon := range graph.getAddonsSucceeded() {
|
|
newAddon := addon.mca.DeepCopy()
|
|
d.setCondition(newAddon, metav1.ConditionTrue, "ConfigurationsConfigured", "Configurations configured")
|
|
|
|
err := d.patchAddonStatus(ctx, newAddon, addon.mca)
|
|
if err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
|
|
if len(errs) > 0 {
|
|
return cma, reconcileContinue, utilerrors.NewAggregate(errs)
|
|
}
|
|
|
|
if graph.getRequeueTime() < maxRequeueTime {
|
|
return cma, reconcileContinue, helpers.NewRequeueError("Rollout requeue", graph.getRequeueTime())
|
|
}
|
|
|
|
return cma, reconcileContinue, nil
|
|
}
|
|
|
|
func (d *managedClusterAddonConfigurationReconciler) mergeAddonConfig(
|
|
mca *addonv1beta1.ManagedClusterAddOn, desiredConfigMap addonConfigMap) *addonv1beta1.ManagedClusterAddOn {
|
|
mcaCopy := mca.DeepCopy()
|
|
|
|
mergedConfigs := make(addonConfigMap)
|
|
// First go through the configReferences listed in mca status,
|
|
// if the existing config (gvk + namespace + name) is also in the desiredConfigMap, append it to mergedConfigs,
|
|
// this will save the LastAppliedConfig and LastObservedGeneration from mca status.
|
|
for _, configRef := range mcaCopy.Status.ConfigReferences {
|
|
gr := configRef.ConfigGroupResource
|
|
if _, ok := mergedConfigs[gr]; !ok {
|
|
mergedConfigs[gr] = []addonv1beta1.ConfigReference{}
|
|
}
|
|
if _, ok := desiredConfigMap.containsConfig(gr, configRef.DesiredConfig.ConfigReferent); ok {
|
|
mergedConfigs[gr] = append(mergedConfigs[gr], configRef)
|
|
}
|
|
}
|
|
|
|
// Then go through the desiredConfigMap, for each configReference,
|
|
// if the desired config (gvk + namespace + name) is aleady in the mergedConfigs,
|
|
// update the ConfigReferent and DesiredConfig (including desired spechash) to mergedConfigs.
|
|
// else just append it to the mergedConfigs.
|
|
for gr, configReferences := range desiredConfigMap {
|
|
for _, configRef := range configReferences {
|
|
if _, ok := mergedConfigs[gr]; !ok {
|
|
mergedConfigs[gr] = []addonv1beta1.ConfigReference{}
|
|
}
|
|
|
|
referent := configRef.DesiredConfig.ConfigReferent
|
|
if i, exist := mergedConfigs.containsConfig(gr, referent); exist {
|
|
mergedConfigs[gr][i].DesiredConfig = configRef.DesiredConfig.DeepCopy()
|
|
} else {
|
|
mergedConfigs[gr] = append(mergedConfigs[gr], configRef)
|
|
}
|
|
}
|
|
}
|
|
|
|
// sort by gvk and set the final config references
|
|
configRefs := []addonv1beta1.ConfigReference{}
|
|
for _, gvk := range mergedConfigs.orderedKeys() {
|
|
configRefs = append(configRefs, mergedConfigs[gvk]...)
|
|
}
|
|
mcaCopy.Status.ConfigReferences = configRefs
|
|
return mcaCopy
|
|
}
|
|
|
|
// setCondition updates the configured condition for the addon
|
|
func (d *managedClusterAddonConfigurationReconciler) setCondition(
|
|
addon *addonv1beta1.ManagedClusterAddOn, status metav1.ConditionStatus, reason, message string) {
|
|
meta.SetStatusCondition(&addon.Status.Conditions, metav1.Condition{
|
|
Type: addonv1beta1.ManagedClusterAddOnConditionConfigured,
|
|
Status: status,
|
|
Reason: reason,
|
|
Message: message,
|
|
})
|
|
}
|
|
|
|
// patchAddonStatus patches the status of the addon
|
|
func (d *managedClusterAddonConfigurationReconciler) patchAddonStatus(
|
|
ctx context.Context, newaddon *addonv1beta1.ManagedClusterAddOn, oldaddon *addonv1beta1.ManagedClusterAddOn) error {
|
|
patcher := patcher.NewPatcher[
|
|
*addonv1beta1.ManagedClusterAddOn, addonv1beta1.ManagedClusterAddOnSpec, addonv1beta1.ManagedClusterAddOnStatus](
|
|
d.addonClient.AddonV1beta1().ManagedClusterAddOns(newaddon.Namespace))
|
|
|
|
_, err := patcher.PatchStatus(ctx, newaddon, newaddon.Status, oldaddon.Status)
|
|
return err
|
|
}
|