Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This new controller reconciles the status of the NamespaceOffloading resource. It checks every 'n' seconds the actual status of all remote namespaces associated with that NamespaceOffloading resource, by means of NamespaceMap Status. So based on these just read values, the controller sets the global offloading status and the remote namespace condition in the NamespaceOffloading Status.
- Loading branch information
1 parent
7b2b9f0
commit adc07a4
Showing
7 changed files
with
928 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 2 additions & 0 deletions
2
pkg/liqo-controller-manager/offloadingStatus-controller/doc.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// Package offloadingstatuscontroller contains OffloadingStatus Controller logic. | ||
package offloadingstatuscontroller |
131 changes: 131 additions & 0 deletions
131
...o-controller-manager/offloadingStatus-controller/namespaceoffloading_status_management.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
package offloadingstatuscontroller | ||
|
||
import ( | ||
corev1 "k8s.io/api/core/v1" | ||
"k8s.io/klog" | ||
|
||
offv1alpha1 "github.com/liqotech/liqo/apis/offloading/v1alpha1" | ||
mapsv1alpha1 "github.com/liqotech/liqo/apis/virtualKubelet/v1alpha1" | ||
liqoconst "github.com/liqotech/liqo/pkg/consts" | ||
liqoutils "github.com/liqotech/liqo/pkg/utils" | ||
) | ||
|
||
// mapPhaseToRemoteNamespaceCondition selects the right remote condition according to the remote namespace | ||
// phase obtained by means of NamespaceMap.Status.CurrentMapping. | ||
func mapPhaseToRemoteNamespaceCondition(phase mapsv1alpha1.MappingPhase) offv1alpha1.RemoteNamespaceCondition { | ||
var remoteCondition offv1alpha1.RemoteNamespaceCondition | ||
switch { | ||
case phase == mapsv1alpha1.MappingAccepted: | ||
remoteCondition = offv1alpha1.RemoteNamespaceCondition{ | ||
Type: offv1alpha1.NamespaceReady, | ||
Status: corev1.ConditionTrue, | ||
Reason: "RemoteNamespaceCreated", | ||
Message: "Namespace correctly offloaded on this cluster", | ||
} | ||
case phase == mapsv1alpha1.MappingCreationLoopBackOff: | ||
remoteCondition = offv1alpha1.RemoteNamespaceCondition{ | ||
Type: offv1alpha1.NamespaceReady, | ||
Status: corev1.ConditionFalse, | ||
Reason: "CreationLoopBackOff", | ||
Message: "Some problems occurred during remote Namespace creation", | ||
} | ||
case phase == mapsv1alpha1.MappingTerminating: | ||
remoteCondition = offv1alpha1.RemoteNamespaceCondition{ | ||
Type: offv1alpha1.NamespaceReady, | ||
Status: corev1.ConditionFalse, | ||
Reason: "TerminatingNamespace", | ||
Message: "The remote Namespace is requested to be deleted", | ||
} | ||
// If phase is not specified. | ||
default: | ||
remoteCondition = offv1alpha1.RemoteNamespaceCondition{ | ||
Type: offv1alpha1.NamespaceOffloadingRequired, | ||
Status: corev1.ConditionFalse, | ||
Reason: "ClusterNotSelected", | ||
Message: "You have not selected this cluster through ClusterSelector fields", | ||
} | ||
} | ||
return remoteCondition | ||
} | ||
|
||
// assignClusterRemoteCondition sets the right remote namespace condition according to the remote namespace phase | ||
// written in NamespaceMap.Status.CurrentMapping. | ||
// If phase==nil the remote namespace condition OffloadingRequired=False is set. | ||
func assignClusterRemoteCondition(noff *offv1alpha1.NamespaceOffloading, phase mapsv1alpha1.MappingPhase, clusterID string) { | ||
if noff.Status.RemoteNamespacesConditions == nil { | ||
noff.Status.RemoteNamespacesConditions = map[string]offv1alpha1.RemoteNamespaceConditions{} | ||
} | ||
|
||
newCondition := mapPhaseToRemoteNamespaceCondition(phase) | ||
// if the condition is already there, do nothing | ||
if liqoutils.IsStatusConditionPresentAndEqual(noff.Status.RemoteNamespacesConditions[clusterID], newCondition.Type, newCondition.Status) { | ||
return | ||
} | ||
var remoteConditions []offv1alpha1.RemoteNamespaceCondition | ||
liqoutils.AddRemoteNamespaceCondition(&remoteConditions, &newCondition) | ||
noff.Status.RemoteNamespacesConditions[clusterID] = remoteConditions | ||
klog.Infof("Remote condition of type '%s' with Status '%s' for the remote namespace '%s' associated with the cluster '%s'", | ||
remoteConditions[0].Type, remoteConditions[0].Status, noff.Namespace, clusterID) | ||
} | ||
|
||
// todo: at the moment the global status InProgress is not implemented, at every reconcile the controller sets a global | ||
// OffloadingStatus that reflects the current Status of NamespaceMaps | ||
// If the NamespaceMap has a remote Status for that remote Namespace, the right remote condition is set according to the | ||
// remote Namespace Phase. If there is no remote Status in the NamespaceMap, the OffloadingRequired=false condition is set | ||
// this condition could be only transient until the NamespaceMap Status is updated or permanent if the local Namespace | ||
// is not requested to be offloaded inside this cluster. | ||
func setRemoteConditionsForEveryCluster(noff *offv1alpha1.NamespaceOffloading, nml *mapsv1alpha1.NamespaceMapList) { | ||
for i := range nml.Items { | ||
if remoteNamespaceStatus, ok := nml.Items[i].Status.CurrentMapping[noff.Namespace]; ok { | ||
assignClusterRemoteCondition(noff, remoteNamespaceStatus.Phase, nml.Items[i].Labels[liqoconst.RemoteClusterID]) | ||
continue | ||
} | ||
// Two cases in which there are no entry in NamespaceMap Status: | ||
// - when the local namespace is not offloaded inside this cluster. | ||
// - when the remote namespace previously created has been correctly removed from this cluster. | ||
// In these cases the remote condition will be "OffloadingRequired=false" | ||
assignClusterRemoteCondition(noff, "", nml.Items[i].Labels[liqoconst.RemoteClusterID]) | ||
} | ||
} | ||
|
||
// setNamespaceOffloadingStatus sets global offloading status according to the remote namespace conditions. | ||
func setNamespaceOffloadingStatus(noff *offv1alpha1.NamespaceOffloading) { | ||
ready := 0 | ||
notReady := 0 | ||
|
||
for i := range noff.Status.RemoteNamespacesConditions { | ||
condition := liqoutils.FindRemoteNamespaceCondition(noff.Status.RemoteNamespacesConditions[i], offv1alpha1.NamespaceReady) | ||
if condition == nil { | ||
continue | ||
} | ||
if condition.Status == corev1.ConditionTrue { | ||
ready++ | ||
} else { | ||
notReady++ | ||
} | ||
} | ||
|
||
switch { | ||
case !noff.DeletionTimestamp.IsZero(): | ||
noff.Status.OffloadingPhase = offv1alpha1.TerminatingOffloadingPhaseType | ||
if ready+notReady == 0 { | ||
// The NamespaceOffloading is deleted only when there are no more remoteNamespaceCondition and | ||
// the deletion timestamp is set. | ||
for key := range noff.Status.RemoteNamespacesConditions { | ||
delete(noff.Status.RemoteNamespacesConditions, key) | ||
} | ||
klog.Infof("NamespaceOffloading, in the namespace '%s', ready to be deleted", noff.Namespace) | ||
} | ||
case ready+notReady == 0: | ||
noff.Status.OffloadingPhase = offv1alpha1.NoClusterSelectedOffloadingPhaseType | ||
case ready == 0: | ||
noff.Status.OffloadingPhase = offv1alpha1.AllFailedOffloadingPhaseType | ||
case notReady == 0: | ||
noff.Status.OffloadingPhase = offv1alpha1.ReadyOffloadingPhaseType | ||
default: | ||
noff.Status.OffloadingPhase = offv1alpha1.SomeFailedOffloadingPhaseType | ||
} | ||
|
||
klog.Infof("The OffloadingStatus for NamespaceOffloading in the namespace '%s' is set to '%s'", | ||
noff.Namespace, noff.Status.OffloadingPhase) | ||
} |
107 changes: 107 additions & 0 deletions
107
pkg/liqo-controller-manager/offloadingStatus-controller/offloadingstatus_controller.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/* | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package offloadingstatuscontroller | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/types" | ||
"k8s.io/klog" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/event" | ||
"sigs.k8s.io/controller-runtime/pkg/predicate" | ||
|
||
offv1alpha1 "github.com/liqotech/liqo/apis/offloading/v1alpha1" | ||
mapsv1alpha1 "github.com/liqotech/liqo/apis/virtualKubelet/v1alpha1" | ||
liqoconst "github.com/liqotech/liqo/pkg/consts" | ||
) | ||
|
||
// OffloadingStatusReconciler checks the status of all remote namespaces associated with this | ||
// namespaceOffloading Resource, and sets the global offloading status in according to the feedbacks received | ||
// from all remote clusters. | ||
type OffloadingStatusReconciler struct { | ||
client.Client | ||
Scheme *runtime.Scheme | ||
RequeueTime time.Duration | ||
} | ||
|
||
// Controller Ownership: | ||
// --> NamespaceOffloading.Status.RemoteConditions | ||
// --> NamespaceOffloading.Status.OffloadingPhase | ||
|
||
// Reconcile sets the NamespaceOffloading Status checking the actual status of all remote Namespace. | ||
// This reconcile is performed every RequeueTime. | ||
func (r *OffloadingStatusReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { | ||
namespaceOffloading := &offv1alpha1.NamespaceOffloading{} | ||
if err := r.Get(ctx, types.NamespacedName{ | ||
Namespace: req.Namespace, | ||
Name: liqoconst.DefaultNamespaceOffloadingName, | ||
}, namespaceOffloading); err != nil { | ||
if apierrors.IsNotFound(err) { | ||
klog.Infof("There is no NamespaceOffloading resource in Namespace '%s'", req.Namespace) | ||
return ctrl.Result{}, nil | ||
} | ||
klog.Errorf("%s --> Unable to get namespaceOffloading for the namespace '%s'", err, req.Namespace) | ||
return ctrl.Result{}, err | ||
} | ||
|
||
// Get all NamespaceMaps in the cluster | ||
namespaceMapList := &mapsv1alpha1.NamespaceMapList{} | ||
if err := r.List(ctx, namespaceMapList); err != nil { | ||
klog.Errorf("%s -> unable to get NamespaceMaps", err) | ||
return ctrl.Result{}, err | ||
} | ||
|
||
if len(namespaceMapList.Items) == 0 { | ||
klog.Info("No NamespaceMaps in the cluster at the moment") | ||
return ctrl.Result{RequeueAfter: r.RequeueTime}, nil | ||
} | ||
|
||
original := namespaceOffloading.DeepCopy() | ||
|
||
setRemoteConditionsForEveryCluster(namespaceOffloading, namespaceMapList) | ||
|
||
setNamespaceOffloadingStatus(namespaceOffloading) | ||
|
||
// Patch the status just one time at the end of the logic. | ||
if err := r.Patch(ctx, namespaceOffloading, client.MergeFrom(original)); err != nil { | ||
klog.Errorf("%s --> Unable to Patch NamespaceOffloading in the namespace '%s'", | ||
err, namespaceOffloading.Namespace) | ||
return ctrl.Result{}, err | ||
} | ||
|
||
return ctrl.Result{RequeueAfter: r.RequeueTime}, nil | ||
} | ||
|
||
// checkNamespaceOffloadingStatus calls Reconcile only when a new NamespaceOffloading is created. | ||
func checkNamespaceOffloadingStatus() predicate.Predicate { | ||
return predicate.Funcs{ | ||
UpdateFunc: func(e event.UpdateEvent) bool { | ||
return false | ||
}, | ||
} | ||
} | ||
|
||
// SetupWithManager reconciles when a new NamespaceOffloading is created. | ||
func (r *OffloadingStatusReconciler) SetupWithManager(mgr ctrl.Manager) error { | ||
return ctrl.NewControllerManagedBy(mgr). | ||
For(&offv1alpha1.NamespaceOffloading{}). | ||
WithEventFilter(checkNamespaceOffloadingStatus()). | ||
Complete(r) | ||
} |
Oops, something went wrong.