func()

in cns/multitenantcontroller/multitenantoperator/multitenantcrdreconciler.go [48:174]


func (r *multiTenantCrdReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
	logger.Printf("Reconcling MultiTenantNetworkContainer %v", request.NamespacedName.String())

	var nc ncapi.MultiTenantNetworkContainer
	if err := r.KubeClient.Get(ctx, request.NamespacedName, &nc); err != nil {
		if apierrors.IsNotFound(err) {
			logger.Printf("MultiTenantNetworkContainer %s not found, skip reconciling", request.NamespacedName.String())
			return ctrl.Result{}, nil
		}

		logger.Errorf("Failed to fetch network container %s: %v", request.NamespacedName.String(), err)
		return ctrl.Result{}, err
	}

	if !nc.ObjectMeta.DeletionTimestamp.IsZero() {
		// Do nothing if the NC has already in Terminated state.
		if nc.Status.State == NCStateTerminated {
			logger.Printf("MultiTenantNetworkContainer %s already terminated, skip reconciling", request.NamespacedName.String())
			return ctrl.Result{}, nil
		}

		// Remove the deleted network container from CNS.
		responseCode := r.CNSRestService.DeleteNetworkContainerInternal(cns.DeleteNetworkContainerRequest{
			NetworkContainerid: nc.Spec.UUID,
		})
		err := restserver.ResponseCodeToError(responseCode)
		if err != nil {
			logger.Errorf("Failed to delete NC %s (UUID: %s) from CNS: %v", request.NamespacedName.String(), nc.Spec.UUID, err)
			return ctrl.Result{}, err
		}

		// Update NC state to Terminated.
		nc.Status.State = NCStateTerminated
		if err := r.KubeClient.Status().Update(ctx, &nc); err != nil {
			logger.Errorf("Failed to update network container state for %s (UUID: %s): %v", request.NamespacedName.String(), nc.Spec.UUID, err)
			return ctrl.Result{}, err
		}

		logger.Printf("NC has been terminated for %s (UUID: %s)", request.NamespacedName.String(), nc.Spec.UUID)
		return ctrl.Result{}, nil
	}

	// Do nothing if the network container hasn't been initialized yet from control plane.
	if nc.Status.State != NCStateInitialized {
		logger.Printf("MultiTenantNetworkContainer %s hasn't initialized yet, skip reconciling", request.NamespacedName.String())
		return ctrl.Result{}, nil
	}

	// Parse KubernetesPodInfo as orchestratorContext.
	podInfo := cns.KubernetesPodInfo{
		PodName:      nc.Name,
		PodNamespace: nc.Namespace,
	}
	orchestratorContext, err := json.Marshal(podInfo)
	if err != nil {
		logger.Errorf("Failed to marshal podInfo (%v): %v", podInfo, err)
		return ctrl.Result{}, err
	}

	// Check CNS NC states.
	_, returnCode := r.CNSRestService.GetNetworkContainerInternal(cns.GetNetworkContainerRequest{
		NetworkContainerid:  nc.Spec.UUID,
		OrchestratorContext: orchestratorContext,
	})
	err = restserver.ResponseCodeToError(returnCode)
	if err == nil {
		logger.Printf("NC %s (UUID: %s) has already been created in CNS", request.NamespacedName.String(), nc.Spec.UUID)
		return ctrl.Result{}, nil
	}

	// return any error except UnknownContainerID
	var cnsRESTErr *restserver.CNSRESTError
	if !errors.As(err, &cnsRESTErr) || cnsRESTErr.ResponseCode != types.UnknownContainerID {
		logger.Errorf("Failed to fetch NC %s (UUID: %s) from CNS: %v", request.NamespacedName.String(), nc.Spec.UUID, err)
		return ctrl.Result{}, err
	}

	// Check that the MultiTenantInfo is set
	if reflect.DeepEqual(ncapi.MultiTenantInfo{}, nc.Status.MultiTenantInfo) {
		logger.Errorf("expected NC status multitenant info to not be empty for object %s", request.NamespacedName)
		// There is no reason to requeue since we will reconcile this object when the multitenant info is added
		return ctrl.Result{}, nil
	}

	// Persist NC states into CNS.
	_, ipNet, err := net.ParseCIDR(nc.Status.IPSubnet)
	if err != nil {
		logger.Errorf("Failed to parse IPSubnet %s for NC %s: %v", nc.Status.IPSubnet, nc.Spec.UUID, err)
		return ctrl.Result{}, err
	}
	prefixLength, _ := ipNet.Mask.Size()
	networkContainerRequest := &cns.CreateNetworkContainerRequest{
		NetworkContainerid:   nc.Spec.UUID,
		OrchestratorContext:  orchestratorContext,
		NetworkContainerType: cns.Kubernetes,
		Version:              "0",
		IPConfiguration: cns.IPConfiguration{
			IPSubnet: cns.IPSubnet{
				IPAddress:    nc.Status.IP,
				PrefixLength: uint8(prefixLength),
			},
			GatewayIPAddress: nc.Status.Gateway,
		},
		PrimaryInterfaceIdentifier: nc.Status.PrimaryInterfaceIdentifier,
		MultiTenancyInfo: cns.MultiTenancyInfo{
			EncapType: nc.Status.MultiTenantInfo.EncapType,
			ID:        int(nc.Status.MultiTenantInfo.ID),
		},
	}
	logger.Printf("CreateOrUpdateNC with networkContainerRequest: %#v", networkContainerRequest)
	responseCode := r.CNSRestService.CreateOrUpdateNetworkContainerInternal(networkContainerRequest)
	err = restserver.ResponseCodeToError(responseCode)
	if err != nil {
		logger.Errorf("Failed to persist state for NC %s (UUID: %s) to CNS: %v", request.NamespacedName.String(), nc.Spec.UUID, err)
		return ctrl.Result{}, err
	}

	// Update NC state to Succeeded.
	nc.Status.State = NCStateSucceeded
	if err := r.KubeClient.Status().Update(ctx, &nc); err != nil {
		logger.Errorf("Failed to update network container state for %s (UUID: %s): %v", request.NamespacedName.String(), nc.Spec.UUID, err)
		return ctrl.Result{}, err
	}

	logger.Printf("Reconciled NC %s (UUID: %s)", request.NamespacedName.String(), nc.Spec.UUID)
	return reconcile.Result{}, nil
}