halkyon.io/api@v1.0.0-rc.6/v1beta1/commons.go (about)

     1  package v1beta1
     2  
     3  import (
     4  	"fmt"
     5  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     6  	"k8s.io/apimachinery/pkg/runtime/schema"
     7  	"strings"
     8  	"time"
     9  )
    10  
    11  const (
    12  	// See https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
    13  	NameLabelKey           = "app.kubernetes.io/name"
    14  	VersionLabelKey        = "app.kubernetes.io/version"
    15  	InstanceLabelKey       = "app.kubernetes.io/instance"
    16  	PartOfLabelKey         = "app.kubernetes.io/part-of"
    17  	ComponentLabelKey      = "app.kubernetes.io/component"
    18  	ManagedByLabelKey      = "app.kubernetes.io/managed-by"
    19  	RuntimeLabelKey        = "app.openshift.io/runtime"
    20  	RuntimeVersionLabelKey = "app.openshift.io/version"
    21  )
    22  
    23  type NameValuePair struct {
    24  	Name  string `json:"name,omitempty"`
    25  	Value string `json:"value,omitempty"`
    26  }
    27  
    28  // DependentConditionType is a valid value for DependentCondition.Type
    29  type DependentConditionType string
    30  
    31  // These are valid dependent conditions.
    32  const (
    33  	// DependentReady means the dependent is able to service requests.
    34  	DependentReady DependentConditionType = "Ready"
    35  	// DependentPending means that the dependent is still processing.
    36  	DependentPending DependentConditionType = "Pending"
    37  	// DependentFailed means that the dependent is in error and probably requires user intervention to get back to working state.
    38  	DependentFailed DependentConditionType = "Failed"
    39  )
    40  
    41  // DependentCondition contains details for the current condition of the associated DependentResource.
    42  type DependentCondition struct {
    43  	// Type of the condition.
    44  	Type DependentConditionType `json:"type"`
    45  	// Type of the dependent associated with the condition.
    46  	DependentType schema.GroupVersionKind `json:"dependentType"`
    47  	// Name of the dependent associated with the condition.
    48  	DependentName string `json:"dependentName"`
    49  	// Records the last time the condition transitioned from one status to another.
    50  	// +optional
    51  	LastTransitionTime v1.Time `json:"lastTransitionTime,omitempty"`
    52  	// Unique, one-word, CamelCase reason for the condition's last transition.
    53  	// +optional
    54  	Reason string `json:"reason,omitempty"`
    55  	// Human-readable message indicating details about last transition.
    56  	// +optional
    57  	Message string `json:"message,omitempty"`
    58  	// Additional information that the condition wishes to convey/record as name-value pairs.
    59  	// +optional
    60  	Attributes []NameValuePair `json:"attributes,omitempty"`
    61  }
    62  
    63  const (
    64  	// ReasonPending means the entity has been accepted by the system, but it is still being processed. This includes time
    65  	// being instantiated.
    66  	ReasonPending = "Pending"
    67  	// ReasonReady means the entity has been instantiated to a node and all of its dependencies are available. The
    68  	// entity is able to process requests.
    69  	ReasonReady = "Ready"
    70  	// ReasonFailed means that the entity or some of its dependencies have failed and cannot be salvaged without user
    71  	// intervention.
    72  	ReasonFailed = "Failed"
    73  )
    74  
    75  type Status struct {
    76  	LastUpdate v1.Time              `json:"lastUpdate,omitempty"`
    77  	Reason     string               `json:"reason,omitempty"`
    78  	Message    string               `json:"message,omitempty"`
    79  	Conditions []DependentCondition `json:"conditions,omitempty"`
    80  }
    81  
    82  func (in *Status) GetConditionsWith(gvk schema.GroupVersionKind) []DependentCondition {
    83  	if gvk.Empty() {
    84  		return []DependentCondition{}
    85  	}
    86  
    87  	conditions := make([]DependentCondition, 0, len(in.Conditions))
    88  	for _, condition := range in.Conditions {
    89  		if condition.DependentType == gvk {
    90  			conditions = append(conditions, condition)
    91  		}
    92  	}
    93  	return conditions
    94  }
    95  
    96  func (in *Status) GetConditionFor(name string, gvk schema.GroupVersionKind) (existingOrNew *DependentCondition) {
    97  	_, condition := in.indexAndConditionWith(name, gvk)
    98  	return condition
    99  }
   100  
   101  func (in *Status) indexAndConditionWith(name string, gvk schema.GroupVersionKind) (index int, existingOrNew *DependentCondition) {
   102  	if len(name) == 0 || gvk.Empty() {
   103  		panic(fmt.Errorf("a condition needs a name and a gvk"))
   104  	}
   105  	if in.Conditions == nil {
   106  		in.Conditions = make([]DependentCondition, 0, 15)
   107  	}
   108  	for i, condition := range in.Conditions {
   109  		if condition.DependentName == name && condition.DependentType == gvk {
   110  			return i, &condition
   111  		}
   112  	}
   113  	existingOrNew = &DependentCondition{
   114  		DependentType: gvk,
   115  		DependentName: name,
   116  	}
   117  	index = len(in.Conditions)
   118  	in.Conditions = append(in.Conditions, *existingOrNew)
   119  	return
   120  }
   121  
   122  // SetCondition sets the given condition on the Status, returning true if the status has been modified as a result
   123  func (in *Status) SetCondition(condition *DependentCondition) (updated bool) {
   124  	if condition == nil {
   125  		return false
   126  	}
   127  
   128  	// if, for some reason, the index is not set on the condition, retrieve the condition again from the array as this sets the index
   129  	index, previous := in.indexAndConditionWith(condition.DependentName, condition.DependentType)
   130  	if previous == nil || condition.Type != previous.Type || condition.Message != previous.Message {
   131  		condition.Reason = string(condition.Type)
   132  		now := v1.NewTime(time.Now())
   133  		condition.LastTransitionTime = now
   134  		in.LastUpdate = now
   135  		in.Conditions[index] = *condition // update the array with the new condition
   136  		updated = true
   137  	}
   138  
   139  	// re-compute overall status only if the set condition has changed or if we don't already have an overall status
   140  	if updated || len(in.Reason) == 0 {
   141  		overall := ReasonReady
   142  		conditionMessages := make([]string, 0, len(in.Conditions))
   143  		for _, c := range in.Conditions {
   144  			// if the condition isn't ready, then the overall status should be pending
   145  			if !c.IsReady() {
   146  				if len(c.Message) > 0 {
   147  					conditionMessages = append(conditionMessages, c.Message)
   148  				}
   149  				overall = ReasonPending
   150  			}
   151  			// if the condition is failed, then the overall status should be failed
   152  			if c.IsFailed() {
   153  				overall = ReasonFailed
   154  			}
   155  		}
   156  		if in.Reason != overall {
   157  			in.Reason = overall
   158  			updated = true
   159  		}
   160  		msg := strings.Join(conditionMessages, ", ")
   161  		if in.Message != msg {
   162  			in.Message = msg
   163  			updated = true
   164  		}
   165  	}
   166  
   167  	return
   168  }
   169  
   170  func (in *DependentCondition) GetAttribute(name string) string {
   171  	for _, attribute := range in.Attributes {
   172  		if attribute.Name == name {
   173  			return attribute.Value
   174  		}
   175  	}
   176  	return ""
   177  }
   178  
   179  func (in *DependentCondition) SetAttribute(name, value string) string {
   180  	for i, attribute := range in.Attributes {
   181  		if attribute.Name == name {
   182  			in.Attributes[i] = NameValuePair{
   183  				Name:  attribute.Name,
   184  				Value: value,
   185  			}
   186  			return attribute.Value
   187  		}
   188  	}
   189  	in.Attributes = append(in.Attributes, NameValuePair{Name: name, Value: value})
   190  	return ""
   191  }
   192  
   193  func (in *DependentCondition) IsReady() bool {
   194  	return in.Type == DependentReady
   195  }
   196  
   197  func (in *DependentCondition) IsFailed() bool {
   198  	return in.Type == DependentFailed
   199  }
   200  
   201  type StatusAware interface {
   202  	GetStatus() Status
   203  	SetStatus(status Status)
   204  	Handle(err error) (bool, Status)
   205  }
   206  
   207  func (in *DependentCondition) DeepCopyInto(out *DependentCondition) {
   208  	*out = *in
   209  	out.DependentType = in.DependentType
   210  	in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
   211  	if in.Attributes != nil {
   212  		in, out := &in.Attributes, &out.Attributes
   213  		*out = make([]NameValuePair, len(*in))
   214  		copy(*out, *in)
   215  	}
   216  	return
   217  }
   218  
   219  func (in *DependentCondition) DeepCopy() *DependentCondition {
   220  	if in == nil {
   221  		return nil
   222  	}
   223  	out := new(DependentCondition)
   224  	in.DeepCopyInto(out)
   225  	return out
   226  }
   227  
   228  func (in *Status) DeepCopyInto(out *Status) {
   229  	*out = *in
   230  	in.LastUpdate.DeepCopyInto(&out.LastUpdate)
   231  	if in.Conditions != nil {
   232  		in, out := &in.Conditions, &out.Conditions
   233  		*out = make([]DependentCondition, len(*in))
   234  		for i := range *in {
   235  			(*in)[i].DeepCopyInto(&(*out)[i])
   236  		}
   237  	}
   238  	return
   239  }
   240  
   241  func (in *Status) DeepCopy() *Status {
   242  	if in == nil {
   243  		return nil
   244  	}
   245  	out := new(Status)
   246  	in.DeepCopyInto(out)
   247  	return out
   248  }