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

     1  package util
     2  
     3  import (
     4  	"fmt"
     5  
     6  	v1 "k8s.io/api/core/v1"
     7  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     8  
     9  	apiv1 "github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1"
    10  )
    11  
    12  const (
    13  	// JobCreatedReason is added in a job when it is created.
    14  	JobCreatedReason = "Created"
    15  	// JobSucceededReason is added in a job when it is succeeded.
    16  	JobSucceededReason = "Succeeded"
    17  	// JobRunningReason is added in a job when it is running.
    18  	JobRunningReason = "Running"
    19  	// JobFailedReason is added in a job when it is failed.
    20  	JobFailedReason = "Failed"
    21  	// JobRestartingReason is added in a job when it is restarting.
    22  	JobRestartingReason = "Restarting"
    23  	// JobFailedValidationReason is added in a job when it failed validation
    24  	JobFailedValidationReason = "FailedValidation"
    25  	// JobSuspendedReason is added in a job when it is suspended.
    26  	JobSuspendedReason = "Suspended"
    27  	// JobResumedReason is added in a job when it is unsuspended.
    28  	JobResumedReason = "Resumed"
    29  )
    30  
    31  func NewReason(kind, reason string) string {
    32  	return fmt.Sprintf("%s%s", kind, reason)
    33  }
    34  
    35  // IsFinished checks if the job is succeeded or failed
    36  func IsFinished(status apiv1.JobStatus) bool {
    37  	return IsSucceeded(status) || IsFailed(status)
    38  }
    39  
    40  // IsSucceeded checks if the job is succeeded
    41  func IsSucceeded(status apiv1.JobStatus) bool {
    42  	return isStatusConditionTrue(status, apiv1.JobSucceeded)
    43  }
    44  
    45  // IsFailed checks if the job is failed
    46  func IsFailed(status apiv1.JobStatus) bool {
    47  	return isStatusConditionTrue(status, apiv1.JobFailed)
    48  }
    49  
    50  func IsRunning(status apiv1.JobStatus) bool {
    51  	return isStatusConditionTrue(status, apiv1.JobRunning)
    52  }
    53  
    54  func IsSuspended(status apiv1.JobStatus) bool {
    55  	return isStatusConditionTrue(status, apiv1.JobSuspended)
    56  }
    57  
    58  // UpdateJobConditions adds to the jobStatus a new condition if needed, with the conditionType, reason, and message
    59  func UpdateJobConditions(
    60  	jobStatus *apiv1.JobStatus,
    61  	conditionType apiv1.JobConditionType,
    62  	conditionStatus v1.ConditionStatus,
    63  	reason, message string,
    64  ) {
    65  	condition := newCondition(conditionType, conditionStatus, reason, message)
    66  	setCondition(jobStatus, condition)
    67  }
    68  
    69  func isStatusConditionTrue(status apiv1.JobStatus, condType apiv1.JobConditionType) bool {
    70  	for _, condition := range status.Conditions {
    71  		if condition.Type == condType && condition.Status == v1.ConditionTrue {
    72  			return true
    73  		}
    74  	}
    75  	return false
    76  }
    77  
    78  // newCondition creates a new job condition.
    79  func newCondition(conditionType apiv1.JobConditionType, conditionStatus v1.ConditionStatus, reason, message string) apiv1.JobCondition {
    80  	return apiv1.JobCondition{
    81  		Type:               conditionType,
    82  		Status:             conditionStatus,
    83  		LastUpdateTime:     metav1.Now(),
    84  		LastTransitionTime: metav1.Now(),
    85  		Reason:             reason,
    86  		Message:            message,
    87  	}
    88  }
    89  
    90  // getCondition returns the condition with the provided type.
    91  func getCondition(status apiv1.JobStatus, condType apiv1.JobConditionType) *apiv1.JobCondition {
    92  	for _, condition := range status.Conditions {
    93  		if condition.Type == condType {
    94  			return &condition
    95  		}
    96  	}
    97  	return nil
    98  }
    99  
   100  // setCondition updates the job to include the provided condition.
   101  // If the condition that we are about to add already exists
   102  // and has the same status and reason then we are not going to update.
   103  func setCondition(status *apiv1.JobStatus, condition apiv1.JobCondition) {
   104  	// Do nothing if JobStatus have failed condition
   105  	if IsFailed(*status) {
   106  		return
   107  	}
   108  
   109  	currentCond := getCondition(*status, condition.Type)
   110  
   111  	// Do nothing if condition doesn't change
   112  	if currentCond != nil && currentCond.Status == condition.Status && currentCond.Reason == condition.Reason {
   113  		return
   114  	}
   115  
   116  	// Do not update lastTransitionTime if the status of the condition doesn't change.
   117  	if currentCond != nil && currentCond.Status == condition.Status {
   118  		condition.LastTransitionTime = currentCond.LastTransitionTime
   119  	}
   120  
   121  	// Append the updated condition to the conditions
   122  	newConditions := filterOutCondition(status.Conditions, condition.Type)
   123  	status.Conditions = append(newConditions, condition)
   124  }
   125  
   126  // filterOutCondition returns a new slice of job conditions without conditions with the provided type.
   127  func filterOutCondition(conditions []apiv1.JobCondition, condType apiv1.JobConditionType) []apiv1.JobCondition {
   128  	var newConditions []apiv1.JobCondition
   129  	for _, c := range conditions {
   130  		if condType == apiv1.JobRestarting && c.Type == apiv1.JobRunning {
   131  			continue
   132  		}
   133  		if condType == apiv1.JobRunning && c.Type == apiv1.JobRestarting {
   134  			continue
   135  		}
   136  
   137  		if c.Type == condType {
   138  			continue
   139  		}
   140  
   141  		// Set the running condition status to be false when current condition failed or succeeded
   142  		if (condType == apiv1.JobFailed || condType == apiv1.JobSucceeded) && c.Type == apiv1.JobRunning {
   143  			c.Status = v1.ConditionFalse
   144  		}
   145  
   146  		newConditions = append(newConditions, c)
   147  	}
   148  	return newConditions
   149  }