1/* 2Copyright 2016 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package v1 18 19import ( 20 "bytes" 21 "encoding/json" 22 "errors" 23 "fmt" 24 25 "k8s.io/apimachinery/pkg/fields" 26 "k8s.io/apimachinery/pkg/labels" 27 "k8s.io/apimachinery/pkg/selection" 28 "k8s.io/apimachinery/pkg/types" 29) 30 31// LabelSelectorAsSelector converts the LabelSelector api type into a struct that implements 32// labels.Selector 33// Note: This function should be kept in sync with the selector methods in pkg/labels/selector.go 34func LabelSelectorAsSelector(ps *LabelSelector) (labels.Selector, error) { 35 if ps == nil { 36 return labels.Nothing(), nil 37 } 38 if len(ps.MatchLabels)+len(ps.MatchExpressions) == 0 { 39 return labels.Everything(), nil 40 } 41 selector := labels.NewSelector() 42 for k, v := range ps.MatchLabels { 43 r, err := labels.NewRequirement(k, selection.Equals, []string{v}) 44 if err != nil { 45 return nil, err 46 } 47 selector = selector.Add(*r) 48 } 49 for _, expr := range ps.MatchExpressions { 50 var op selection.Operator 51 switch expr.Operator { 52 case LabelSelectorOpIn: 53 op = selection.In 54 case LabelSelectorOpNotIn: 55 op = selection.NotIn 56 case LabelSelectorOpExists: 57 op = selection.Exists 58 case LabelSelectorOpDoesNotExist: 59 op = selection.DoesNotExist 60 default: 61 return nil, fmt.Errorf("%q is not a valid pod selector operator", expr.Operator) 62 } 63 r, err := labels.NewRequirement(expr.Key, op, append([]string(nil), expr.Values...)) 64 if err != nil { 65 return nil, err 66 } 67 selector = selector.Add(*r) 68 } 69 return selector, nil 70} 71 72// LabelSelectorAsMap converts the LabelSelector api type into a map of strings, ie. the 73// original structure of a label selector. Operators that cannot be converted into plain 74// labels (Exists, DoesNotExist, NotIn, and In with more than one value) will result in 75// an error. 76func LabelSelectorAsMap(ps *LabelSelector) (map[string]string, error) { 77 if ps == nil { 78 return nil, nil 79 } 80 selector := map[string]string{} 81 for k, v := range ps.MatchLabels { 82 selector[k] = v 83 } 84 for _, expr := range ps.MatchExpressions { 85 switch expr.Operator { 86 case LabelSelectorOpIn: 87 if len(expr.Values) != 1 { 88 return selector, fmt.Errorf("operator %q without a single value cannot be converted into the old label selector format", expr.Operator) 89 } 90 // Should we do anything in case this will override a previous key-value pair? 91 selector[expr.Key] = expr.Values[0] 92 case LabelSelectorOpNotIn, LabelSelectorOpExists, LabelSelectorOpDoesNotExist: 93 return selector, fmt.Errorf("operator %q cannot be converted into the old label selector format", expr.Operator) 94 default: 95 return selector, fmt.Errorf("%q is not a valid selector operator", expr.Operator) 96 } 97 } 98 return selector, nil 99} 100 101// ParseToLabelSelector parses a string representing a selector into a LabelSelector object. 102// Note: This function should be kept in sync with the parser in pkg/labels/selector.go 103func ParseToLabelSelector(selector string) (*LabelSelector, error) { 104 reqs, err := labels.ParseToRequirements(selector) 105 if err != nil { 106 return nil, fmt.Errorf("couldn't parse the selector string \"%s\": %v", selector, err) 107 } 108 109 labelSelector := &LabelSelector{ 110 MatchLabels: map[string]string{}, 111 MatchExpressions: []LabelSelectorRequirement{}, 112 } 113 for _, req := range reqs { 114 var op LabelSelectorOperator 115 switch req.Operator() { 116 case selection.Equals, selection.DoubleEquals: 117 vals := req.Values() 118 if vals.Len() != 1 { 119 return nil, fmt.Errorf("equals operator must have exactly one value") 120 } 121 val, ok := vals.PopAny() 122 if !ok { 123 return nil, fmt.Errorf("equals operator has exactly one value but it cannot be retrieved") 124 } 125 labelSelector.MatchLabels[req.Key()] = val 126 continue 127 case selection.In: 128 op = LabelSelectorOpIn 129 case selection.NotIn: 130 op = LabelSelectorOpNotIn 131 case selection.Exists: 132 op = LabelSelectorOpExists 133 case selection.DoesNotExist: 134 op = LabelSelectorOpDoesNotExist 135 case selection.GreaterThan, selection.LessThan: 136 // Adding a separate case for these operators to indicate that this is deliberate 137 return nil, fmt.Errorf("%q isn't supported in label selectors", req.Operator()) 138 default: 139 return nil, fmt.Errorf("%q is not a valid label selector operator", req.Operator()) 140 } 141 labelSelector.MatchExpressions = append(labelSelector.MatchExpressions, LabelSelectorRequirement{ 142 Key: req.Key(), 143 Operator: op, 144 Values: req.Values().List(), 145 }) 146 } 147 return labelSelector, nil 148} 149 150// SetAsLabelSelector converts the labels.Set object into a LabelSelector api object. 151func SetAsLabelSelector(ls labels.Set) *LabelSelector { 152 if ls == nil { 153 return nil 154 } 155 156 selector := &LabelSelector{ 157 MatchLabels: make(map[string]string), 158 } 159 for label, value := range ls { 160 selector.MatchLabels[label] = value 161 } 162 163 return selector 164} 165 166// FormatLabelSelector convert labelSelector into plain string 167func FormatLabelSelector(labelSelector *LabelSelector) string { 168 selector, err := LabelSelectorAsSelector(labelSelector) 169 if err != nil { 170 return "<error>" 171 } 172 173 l := selector.String() 174 if len(l) == 0 { 175 l = "<none>" 176 } 177 return l 178} 179 180func ExtractGroupVersions(l *APIGroupList) []string { 181 var groupVersions []string 182 for _, g := range l.Groups { 183 for _, gv := range g.Versions { 184 groupVersions = append(groupVersions, gv.GroupVersion) 185 } 186 } 187 return groupVersions 188} 189 190// HasAnnotation returns a bool if passed in annotation exists 191func HasAnnotation(obj ObjectMeta, ann string) bool { 192 _, found := obj.Annotations[ann] 193 return found 194} 195 196// SetMetaDataAnnotation sets the annotation and value 197func SetMetaDataAnnotation(obj *ObjectMeta, ann string, value string) { 198 if obj.Annotations == nil { 199 obj.Annotations = make(map[string]string) 200 } 201 obj.Annotations[ann] = value 202} 203 204// SingleObject returns a ListOptions for watching a single object. 205func SingleObject(meta ObjectMeta) ListOptions { 206 return ListOptions{ 207 FieldSelector: fields.OneTermEqualSelector("metadata.name", meta.Name).String(), 208 ResourceVersion: meta.ResourceVersion, 209 } 210} 211 212// NewDeleteOptions returns a DeleteOptions indicating the resource should 213// be deleted within the specified grace period. Use zero to indicate 214// immediate deletion. If you would prefer to use the default grace period, 215// use &metav1.DeleteOptions{} directly. 216func NewDeleteOptions(grace int64) *DeleteOptions { 217 return &DeleteOptions{GracePeriodSeconds: &grace} 218} 219 220// NewPreconditionDeleteOptions returns a DeleteOptions with a UID precondition set. 221func NewPreconditionDeleteOptions(uid string) *DeleteOptions { 222 u := types.UID(uid) 223 p := Preconditions{UID: &u} 224 return &DeleteOptions{Preconditions: &p} 225} 226 227// NewUIDPreconditions returns a Preconditions with UID set. 228func NewUIDPreconditions(uid string) *Preconditions { 229 u := types.UID(uid) 230 return &Preconditions{UID: &u} 231} 232 233// NewRVDeletionPrecondition returns a DeleteOptions with a ResourceVersion precondition set. 234func NewRVDeletionPrecondition(rv string) *DeleteOptions { 235 p := Preconditions{ResourceVersion: &rv} 236 return &DeleteOptions{Preconditions: &p} 237} 238 239// HasObjectMetaSystemFieldValues returns true if fields that are managed by the system on ObjectMeta have values. 240func HasObjectMetaSystemFieldValues(meta Object) bool { 241 return !meta.GetCreationTimestamp().Time.IsZero() || 242 len(meta.GetUID()) != 0 243} 244 245// ResetObjectMetaForStatus forces the meta fields for a status update to match the meta fields 246// for a pre-existing object. This is opt-in for new objects with Status subresource. 247func ResetObjectMetaForStatus(meta, existingMeta Object) { 248 meta.SetDeletionTimestamp(existingMeta.GetDeletionTimestamp()) 249 meta.SetGeneration(existingMeta.GetGeneration()) 250 meta.SetSelfLink(existingMeta.GetSelfLink()) 251 meta.SetLabels(existingMeta.GetLabels()) 252 meta.SetAnnotations(existingMeta.GetAnnotations()) 253 meta.SetFinalizers(existingMeta.GetFinalizers()) 254 meta.SetOwnerReferences(existingMeta.GetOwnerReferences()) 255 // managedFields must be preserved since it's been modified to 256 // track changed fields in the status update. 257 //meta.SetManagedFields(existingMeta.GetManagedFields()) 258} 259 260// MarshalJSON implements json.Marshaler 261// MarshalJSON may get called on pointers or values, so implement MarshalJSON on value. 262// http://stackoverflow.com/questions/21390979/custom-marshaljson-never-gets-called-in-go 263func (f FieldsV1) MarshalJSON() ([]byte, error) { 264 if f.Raw == nil { 265 return []byte("null"), nil 266 } 267 return f.Raw, nil 268} 269 270// UnmarshalJSON implements json.Unmarshaler 271func (f *FieldsV1) UnmarshalJSON(b []byte) error { 272 if f == nil { 273 return errors.New("metav1.Fields: UnmarshalJSON on nil pointer") 274 } 275 if !bytes.Equal(b, []byte("null")) { 276 f.Raw = append(f.Raw[0:0], b...) 277 } 278 return nil 279} 280 281var _ json.Marshaler = FieldsV1{} 282var _ json.Unmarshaler = &FieldsV1{} 283