github.com/kubeflow/training-operator@v1.7.0/pkg/common/util/reconciler_generic.go (about)

     1  // Copyright 2021 The Kubeflow Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License
    14  
    15  package util
    16  
    17  import (
    18  	"fmt"
    19  	"reflect"
    20  	"strings"
    21  
    22  	log "github.com/sirupsen/logrus"
    23  
    24  	kubeflowv1 "github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1"
    25  	"github.com/kubeflow/training-operator/pkg/controller.v1/common"
    26  	"github.com/kubeflow/training-operator/pkg/controller.v1/expectation"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"sigs.k8s.io/controller-runtime/pkg/event"
    29  )
    30  
    31  // GenExpectationGenericKey generates an expectation key for {Kind} of a job
    32  func GenExpectationGenericKey(jobKey string, replicaType string, pl string) string {
    33  	return jobKey + "/" + strings.ToLower(replicaType) + "/" + pl
    34  }
    35  
    36  // LoggerForGenericKind generates log entry for generic Kubernetes resource Kind
    37  func LoggerForGenericKind(obj metav1.Object, kind string) *log.Entry {
    38  	job := ""
    39  	if controllerRef := metav1.GetControllerOf(obj); controllerRef != nil {
    40  		if controllerRef.Kind == kind {
    41  			job = obj.GetNamespace() + "." + controllerRef.Name
    42  		}
    43  	}
    44  	return log.WithFields(log.Fields{
    45  		// We use job to match the key used in controller.go
    46  		// In controller.go we log the key used with the workqueue.
    47  		"job": job,
    48  		kind:  obj.GetNamespace() + "." + obj.GetName(),
    49  		"uid": obj.GetUID(),
    50  	})
    51  }
    52  
    53  // OnDependentCreateFuncGeneric modify expectations when dependent (pod/service) creation observed.
    54  func OnDependentCreateFuncGeneric(exp expectation.ControllerExpectationsInterface) func(event.CreateEvent) bool {
    55  	return func(e event.CreateEvent) bool {
    56  		rtype := e.Object.GetLabels()[kubeflowv1.ReplicaTypeLabel]
    57  		if len(rtype) == 0 {
    58  			return false
    59  		}
    60  
    61  		if controllerRef := metav1.GetControllerOf(e.Object); controllerRef != nil {
    62  			jobKey := fmt.Sprintf("%s/%s", e.Object.GetNamespace(), controllerRef.Name)
    63  			var expectKey string
    64  			pl := strings.ToLower(e.Object.GetObjectKind().GroupVersionKind().Kind) + "s"
    65  			expectKey = GenExpectationGenericKey(jobKey, rtype, pl)
    66  			exp.CreationObserved(expectKey)
    67  			return true
    68  		}
    69  
    70  		return true
    71  	}
    72  }
    73  
    74  // OnDependentUpdateFuncGeneric modify expectations when dependent (pod/service) update observed.
    75  func OnDependentUpdateFuncGeneric(jc *common.JobController) func(updateEvent event.UpdateEvent) bool {
    76  	return func(e event.UpdateEvent) bool {
    77  		newObj := e.ObjectNew
    78  		oldObj := e.ObjectOld
    79  		if newObj.GetResourceVersion() == oldObj.GetResourceVersion() {
    80  			// Periodic resync will send update events for all known pods.
    81  			// Two different versions of the same pod will always have different RVs.
    82  			return false
    83  		}
    84  
    85  		kind := jc.Controller.GetAPIGroupVersionKind().Kind
    86  		var logger = LoggerForGenericKind(newObj, kind)
    87  
    88  		newControllerRef := metav1.GetControllerOf(newObj)
    89  		oldControllerRef := metav1.GetControllerOf(oldObj)
    90  		controllerRefChanged := !reflect.DeepEqual(newControllerRef, oldControllerRef)
    91  
    92  		if controllerRefChanged && oldControllerRef != nil {
    93  			// The ControllerRef was changed. Sync the old controller, if any.
    94  			if job := resolveControllerRef(jc, oldObj.GetNamespace(), oldControllerRef); job != nil {
    95  				logger.Infof("%s controller ref updated: %v, %v", kind, newObj, oldObj)
    96  				return true
    97  			}
    98  		}
    99  
   100  		// If it has a controller ref, that's all that matters.
   101  		if newControllerRef != nil {
   102  			job := resolveControllerRef(jc, newObj.GetNamespace(), newControllerRef)
   103  			if job == nil {
   104  				return false
   105  			}
   106  			logger.Debugf("%s has a controller ref: %v, %v", kind, newObj, oldObj)
   107  			return true
   108  		}
   109  		return false
   110  	}
   111  }
   112  
   113  // OnDependentDeleteFuncGeneric modify expectations when dependent (pod/service) deletion observed.
   114  func OnDependentDeleteFuncGeneric(exp expectation.ControllerExpectationsInterface) func(event.DeleteEvent) bool {
   115  	return func(e event.DeleteEvent) bool {
   116  
   117  		rtype := e.Object.GetLabels()[kubeflowv1.ReplicaTypeLabel]
   118  		if len(rtype) == 0 {
   119  			return false
   120  		}
   121  
   122  		if controllerRef := metav1.GetControllerOf(e.Object); controllerRef != nil {
   123  			jobKey := fmt.Sprintf("%s/%s", e.Object.GetNamespace(), controllerRef.Name)
   124  			pl := strings.ToLower(e.Object.GetObjectKind().GroupVersionKind().Kind) + "s"
   125  			var expectKey = GenExpectationGenericKey(jobKey, rtype, pl)
   126  
   127  			exp.DeletionObserved(expectKey)
   128  			return true
   129  		}
   130  
   131  		return true
   132  	}
   133  }