blob: ad989ad75cacde75737a3ed6dd6dc333c5b99931 [file] [log] [blame]
Matteo Scandoloa4285862020-12-01 18:10:10 -08001/*
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{}