func()

in pkg/controllers/hub/trafficmanagerbackend/controller.go [495:564]


func (r *Reconciler) validateAndProcessServiceImportForBackend(ctx context.Context, backend *fleetnetv1beta1.TrafficManagerBackend, serviceImport *fleetnetv1alpha1.ServiceImport) (map[string]desiredEndpoint, map[string]error, error) {
	backendKObj := klog.KObj(backend)
	serviceImportKObj := klog.KObj(serviceImport)

	if len(serviceImport.Status.Clusters) == 0 {
		klog.V(2).InfoS("No clusters found in the serviceImport", "trafficManagerBackend", backendKObj, "serviceImport", serviceImportKObj)
		// Controller will only create the serviceImport when there is a cluster exposing their services.
		// Updating the status will be in a separate call and could fail.
		setUnknownCondition(backend, "In the process of exporting the services")
		// We don't need to requeue the request and when the serviceImport status is set, the controller will be re-triggered.
		return nil, nil, r.updateTrafficManagerBackendStatus(ctx, backend)
	}

	internalServiceExportList := &fleetnetv1alpha1.InternalServiceExportList{}
	namespaceName := types.NamespacedName{Namespace: serviceImport.Namespace, Name: serviceImport.Name}
	listOpts := client.MatchingFields{
		exportedServiceFieldNamespacedName: namespaceName.String(),
	}
	if listErr := r.Client.List(ctx, internalServiceExportList, &listOpts); listErr != nil {
		klog.ErrorS(listErr, "Failed to list internalServiceExports used by the serviceImport", "trafficManagerBackend", backendKObj, "serviceImport", serviceImportKObj)
		setUnknownCondition(backend, fmt.Sprintf("Failed to list the exported service %q: %v", namespaceName, listErr))
		if err := r.updateTrafficManagerBackendStatus(ctx, backend); err != nil {
			return nil, nil, err
		}
		return nil, nil, listErr
	}
	internalServiceExportMap := make(map[string]*fleetnetv1alpha1.InternalServiceExport, len(internalServiceExportList.Items))
	for i, export := range internalServiceExportList.Items {
		internalServiceExportMap[export.Spec.ServiceReference.ClusterID] = &internalServiceExportList.Items[i]
	}

	desiredEndpoints := make(map[string]desiredEndpoint, len(serviceImport.Status.Clusters)) // key is the endpoint name
	invalidServices := make(map[string]error, len(serviceImport.Status.Clusters))            // key is cluster name
	var totalWeight int64
	for _, clusterStatus := range serviceImport.Status.Clusters {
		internalServiceExport, ok := internalServiceExportMap[clusterStatus.Cluster]
		if !ok {
			getErr := fmt.Errorf("failed to find the internalServiceExport for the cluster %q", clusterStatus.Cluster)
			// Usually controller should update the serviceImport status first before deleting the internalServiceImport.
			// It could happen that the current serviceImport has stale information.
			// The controller will be re-triggered when the serviceImport is updated.
			klog.ErrorS(getErr, "InternalServiceExport not found for the cluster", "trafficManagerBackend", backendKObj, "serviceImport", serviceImportKObj, "clusterID", clusterStatus.Cluster)
			setUnknownCondition(backend, fmt.Sprintf("Failed to find the exported service %q for %q: %v", namespaceName, clusterStatus.Cluster, getErr))
			return nil, nil, r.updateTrafficManagerBackendStatus(ctx, backend)
		}
		if err := isValidTrafficManagerEndpoint(internalServiceExport); err != nil {
			invalidServices[clusterStatus.Cluster] = err
			klog.V(2).InfoS("Invalid service for TrafficManager endpoint", "trafficManagerBackend", backendKObj, "serviceImport", serviceImportKObj, "clusterID", clusterStatus.Cluster, "error", err)
			continue
		}
		endpoint := generateAzureTrafficManagerEndpoint(backend, internalServiceExport)
		desiredEndpoints[*endpoint.Name] = desiredEndpoint{
			Endpoint: endpoint,
			FromCluster: fleetnetv1beta1.FromCluster{
				ClusterStatus: fleetnetv1beta1.ClusterStatus{
					Cluster: clusterStatus.Cluster,
				},
				Weight: endpoint.Properties.Weight,
			},
		}
		totalWeight += *endpoint.Properties.Weight
	}
	for _, dp := range desiredEndpoints {
		// Calculate the desired weight for the endpoint as the proportion of the total weight.
		desiredWeight := math.Ceil(float64(*backend.Spec.Weight**dp.Endpoint.Properties.Weight) / float64(totalWeight))
		dp.Endpoint.Properties.Weight = ptr.To(int64(desiredWeight))
	}
	klog.V(2).InfoS("Finishing validating services and setup endpoints", "trafficManagerBackend", backendKObj, "serviceImport", serviceImportKObj, "numberOfDesiredEndpoints", len(desiredEndpoints), "numberOfInvalidServices", len(invalidServices), "totalWeight", totalWeight)
	return desiredEndpoints, invalidServices, nil
}