in pkg/controllers/hub/trafficmanagerbackend/controller.go [251:341]
func (r *Reconciler) handleUpdate(ctx context.Context, backend *fleetnetv1beta1.TrafficManagerBackend) (ctrl.Result, error) {
backendKObj := klog.KObj(backend)
profile, err := r.validateTrafficManagerProfile(ctx, backend)
if err != nil || profile == nil {
// We don't need to requeue the invalid Profile (err == nil and profile == nil) because when the profile becomes
// valid, the controller will be re-triggered again.
// The controller will retry when err is not nil.
return ctrl.Result{}, err
}
profileKObj := klog.KObj(profile)
klog.V(2).InfoS("Found the valid trafficManagerProfile", "trafficManagerBackend", backendKObj, "trafficManagerProfile", profileKObj)
atmProfile, err := r.validateAzureTrafficManagerProfile(ctx, backend, profile)
if err != nil || atmProfile == nil {
// We don't need to requeue the invalid Azure Traffic Manager profile (err == nil and atmProfile == nil) as when
// the profile becomes valid, the controller will be re-triggered again.
// The controller will retry when err is not nil.
return ctrl.Result{}, err
}
klog.V(2).InfoS("Found the valid Azure Traffic Manager Profile", "resourceGroup", profile.Spec.ResourceGroup, "trafficManagerBackend", backendKObj, "trafficManagerProfile", profileKObj, "atmProfileName", atmProfile.Name)
serviceImport, err := r.validateServiceImportAndCleanupEndpointsIfInvalid(ctx, profile.Spec.ResourceGroup, backend, atmProfile)
if err != nil || serviceImport == nil {
// We don't need to requeue the invalid serviceImport (err == nil and serviceImport == nil) as when the serviceImport
// becomes valid, the controller will be re-triggered again.
// The controller will retry when err is not nil.
return ctrl.Result{}, err
}
klog.V(2).InfoS("Found the serviceImport", "trafficManagerBackend", backendKObj, "serviceImport", klog.KObj(serviceImport), "clusters", serviceImport.Status.Clusters)
if *backend.Spec.Weight == 0 {
klog.V(2).InfoS("Weight is 0, deleting all the endpoints", "trafficManagerBackend", backendKObj)
if err := r.cleanupEndpoints(ctx, profile.Spec.ResourceGroup, backend, atmProfile); err != nil {
return ctrl.Result{}, err
}
setTrueCondition(backend, nil)
return ctrl.Result{}, r.updateTrafficManagerBackendStatus(ctx, backend)
}
desiredEndpointsMaps, invalidServicesMaps, err := r.validateAndProcessServiceImportForBackend(ctx, backend, serviceImport)
if err != nil || (desiredEndpointsMaps == nil && invalidServicesMaps == nil) {
// We don't need to requeue not found internalServiceExport(err == nil and desiredEndpointsMaps == nil && invalidServicesMaps == nil)
// as when the serviceImport is updated, the controller will be re-triggered again.
// The controller will retry when err is not nil.
return ctrl.Result{}, err
}
klog.V(2).InfoS("Found the exported services behind the serviceImport", "trafficManagerBackend", backendKObj, "serviceImport", klog.KObj(serviceImport), "numberOfDesiredEndpoints", len(desiredEndpointsMaps), "numberOfInvalidServices", len(invalidServicesMaps))
// register finalizer only before creating atm endpoints
// So that when a user specifies an invalid resource group of the profile, the controller will fail to create the endpoint because of the 403 error.
// Otherwise, the deletion will be stuck because of the 403 error and the finalizer cannot be removed.
if !controllerutil.ContainsFinalizer(backend, objectmeta.TrafficManagerBackendFinalizer) {
controllerutil.AddFinalizer(backend, objectmeta.TrafficManagerBackendFinalizer)
if err := r.Update(ctx, backend); err != nil {
klog.ErrorS(err, "Failed to add finalizer to trafficManagerBackend", "trafficManagerBackend", backend)
return ctrl.Result{}, controller.NewUpdateIgnoreConflictError(err)
}
}
acceptedEndpoints, badEndpointsErr, err := r.updateTrafficManagerEndpointsAndUpdateStatusIfUnknown(ctx, profile.Spec.ResourceGroup, backend, atmProfile, desiredEndpointsMaps)
if err != nil {
return ctrl.Result{}, err
}
if len(invalidServicesMaps) == 0 && len(badEndpointsErr) == 0 {
setTrueCondition(backend, acceptedEndpoints)
} else {
var invalidEndpointErrMessage string
if len(badEndpointsErr) > 0 {
invalidEndpointErrMessage = fmt.Sprintf("%v endpoint(s) failed to be created/updated in the Azure Traffic Manager, for example, %v; ", len(badEndpointsErr), badEndpointsErr[0])
}
if len(invalidServicesMaps) > 0 {
for clusterID, invalidServiceErr := range invalidServicesMaps {
invalidEndpointErrMessage = invalidEndpointErrMessage + fmt.Sprintf("%v service(s) exported from clusters cannot be exposed as the Azure Traffic Manager, for example, service exported from %v is invalid: %v", len(invalidServicesMaps), clusterID, invalidServiceErr)
// Here we only populate the message with the first invalid exported service.
// Note, the loop of the invalidServicesMaps is not deterministic.
break
}
}
setFalseCondition(backend, acceptedEndpoints, invalidEndpointErrMessage)
}
klog.V(2).InfoS("Updated Traffic Manager endpoints for the serviceImport and updating the condition", "trafficManagerBackend", backendKObj, "status", backend.Status)
if err := r.updateTrafficManagerBackendStatus(ctx, backend); err != nil {
return ctrl.Result{}, err
}
// If there are any failed endpoints, we need to requeue the request to retry.
// For any invalidService, we don't need to requeue the request as the controller will be re-triggered when the
// serviceImport or internalServiceExport is updated.
return ctrl.Result{}, errors.Join(badEndpointsErr...)
}