blob: b4dc78b3eaa666f03ee38269bb581eac24bc19db [file] [log] [blame]
sslobodrd046be82019-01-16 10:02:22 -05001/*
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 (
Stephane Barbarie260a5632019-02-26 16:12:49 -050020 "encoding/json"
sslobodrd046be82019-01-16 10:02:22 -050021 "fmt"
22
23 "k8s.io/apimachinery/pkg/fields"
24 "k8s.io/apimachinery/pkg/labels"
25 "k8s.io/apimachinery/pkg/selection"
26 "k8s.io/apimachinery/pkg/types"
27)
28
29// LabelSelectorAsSelector converts the LabelSelector api type into a struct that implements
30// labels.Selector
31// Note: This function should be kept in sync with the selector methods in pkg/labels/selector.go
32func LabelSelectorAsSelector(ps *LabelSelector) (labels.Selector, error) {
33 if ps == nil {
34 return labels.Nothing(), nil
35 }
36 if len(ps.MatchLabels)+len(ps.MatchExpressions) == 0 {
37 return labels.Everything(), nil
38 }
39 selector := labels.NewSelector()
40 for k, v := range ps.MatchLabels {
41 r, err := labels.NewRequirement(k, selection.Equals, []string{v})
42 if err != nil {
43 return nil, err
44 }
45 selector = selector.Add(*r)
46 }
47 for _, expr := range ps.MatchExpressions {
48 var op selection.Operator
49 switch expr.Operator {
50 case LabelSelectorOpIn:
51 op = selection.In
52 case LabelSelectorOpNotIn:
53 op = selection.NotIn
54 case LabelSelectorOpExists:
55 op = selection.Exists
56 case LabelSelectorOpDoesNotExist:
57 op = selection.DoesNotExist
58 default:
59 return nil, fmt.Errorf("%q is not a valid pod selector operator", expr.Operator)
60 }
61 r, err := labels.NewRequirement(expr.Key, op, append([]string(nil), expr.Values...))
62 if err != nil {
63 return nil, err
64 }
65 selector = selector.Add(*r)
66 }
67 return selector, nil
68}
69
70// LabelSelectorAsMap converts the LabelSelector api type into a map of strings, ie. the
71// original structure of a label selector. Operators that cannot be converted into plain
72// labels (Exists, DoesNotExist, NotIn, and In with more than one value) will result in
73// an error.
74func LabelSelectorAsMap(ps *LabelSelector) (map[string]string, error) {
75 if ps == nil {
76 return nil, nil
77 }
78 selector := map[string]string{}
79 for k, v := range ps.MatchLabels {
80 selector[k] = v
81 }
82 for _, expr := range ps.MatchExpressions {
83 switch expr.Operator {
84 case LabelSelectorOpIn:
85 if len(expr.Values) != 1 {
86 return selector, fmt.Errorf("operator %q without a single value cannot be converted into the old label selector format", expr.Operator)
87 }
88 // Should we do anything in case this will override a previous key-value pair?
89 selector[expr.Key] = expr.Values[0]
90 case LabelSelectorOpNotIn, LabelSelectorOpExists, LabelSelectorOpDoesNotExist:
91 return selector, fmt.Errorf("operator %q cannot be converted into the old label selector format", expr.Operator)
92 default:
93 return selector, fmt.Errorf("%q is not a valid selector operator", expr.Operator)
94 }
95 }
96 return selector, nil
97}
98
99// ParseToLabelSelector parses a string representing a selector into a LabelSelector object.
100// Note: This function should be kept in sync with the parser in pkg/labels/selector.go
101func ParseToLabelSelector(selector string) (*LabelSelector, error) {
102 reqs, err := labels.ParseToRequirements(selector)
103 if err != nil {
104 return nil, fmt.Errorf("couldn't parse the selector string \"%s\": %v", selector, err)
105 }
106
107 labelSelector := &LabelSelector{
108 MatchLabels: map[string]string{},
109 MatchExpressions: []LabelSelectorRequirement{},
110 }
111 for _, req := range reqs {
112 var op LabelSelectorOperator
113 switch req.Operator() {
114 case selection.Equals, selection.DoubleEquals:
115 vals := req.Values()
116 if vals.Len() != 1 {
117 return nil, fmt.Errorf("equals operator must have exactly one value")
118 }
119 val, ok := vals.PopAny()
120 if !ok {
121 return nil, fmt.Errorf("equals operator has exactly one value but it cannot be retrieved")
122 }
123 labelSelector.MatchLabels[req.Key()] = val
124 continue
125 case selection.In:
126 op = LabelSelectorOpIn
127 case selection.NotIn:
128 op = LabelSelectorOpNotIn
129 case selection.Exists:
130 op = LabelSelectorOpExists
131 case selection.DoesNotExist:
132 op = LabelSelectorOpDoesNotExist
133 case selection.GreaterThan, selection.LessThan:
134 // Adding a separate case for these operators to indicate that this is deliberate
135 return nil, fmt.Errorf("%q isn't supported in label selectors", req.Operator())
136 default:
137 return nil, fmt.Errorf("%q is not a valid label selector operator", req.Operator())
138 }
139 labelSelector.MatchExpressions = append(labelSelector.MatchExpressions, LabelSelectorRequirement{
140 Key: req.Key(),
141 Operator: op,
142 Values: req.Values().List(),
143 })
144 }
145 return labelSelector, nil
146}
147
148// SetAsLabelSelector converts the labels.Set object into a LabelSelector api object.
149func SetAsLabelSelector(ls labels.Set) *LabelSelector {
150 if ls == nil {
151 return nil
152 }
153
154 selector := &LabelSelector{
155 MatchLabels: make(map[string]string),
156 }
157 for label, value := range ls {
158 selector.MatchLabels[label] = value
159 }
160
161 return selector
162}
163
164// FormatLabelSelector convert labelSelector into plain string
165func FormatLabelSelector(labelSelector *LabelSelector) string {
166 selector, err := LabelSelectorAsSelector(labelSelector)
167 if err != nil {
168 return "<error>"
169 }
170
171 l := selector.String()
172 if len(l) == 0 {
173 l = "<none>"
174 }
175 return l
176}
177
178func ExtractGroupVersions(l *APIGroupList) []string {
179 var groupVersions []string
180 for _, g := range l.Groups {
181 for _, gv := range g.Versions {
182 groupVersions = append(groupVersions, gv.GroupVersion)
183 }
184 }
185 return groupVersions
186}
187
188// HasAnnotation returns a bool if passed in annotation exists
189func HasAnnotation(obj ObjectMeta, ann string) bool {
190 _, found := obj.Annotations[ann]
191 return found
192}
193
194// SetMetaDataAnnotation sets the annotation and value
195func SetMetaDataAnnotation(obj *ObjectMeta, ann string, value string) {
196 if obj.Annotations == nil {
197 obj.Annotations = make(map[string]string)
198 }
199 obj.Annotations[ann] = value
200}
201
202// SingleObject returns a ListOptions for watching a single object.
203func SingleObject(meta ObjectMeta) ListOptions {
204 return ListOptions{
205 FieldSelector: fields.OneTermEqualSelector("metadata.name", meta.Name).String(),
206 ResourceVersion: meta.ResourceVersion,
207 }
208}
209
210// NewDeleteOptions returns a DeleteOptions indicating the resource should
211// be deleted within the specified grace period. Use zero to indicate
212// immediate deletion. If you would prefer to use the default grace period,
213// use &metav1.DeleteOptions{} directly.
214func NewDeleteOptions(grace int64) *DeleteOptions {
215 return &DeleteOptions{GracePeriodSeconds: &grace}
216}
217
218// NewPreconditionDeleteOptions returns a DeleteOptions with a UID precondition set.
219func NewPreconditionDeleteOptions(uid string) *DeleteOptions {
220 u := types.UID(uid)
221 p := Preconditions{UID: &u}
222 return &DeleteOptions{Preconditions: &p}
223}
224
225// NewUIDPreconditions returns a Preconditions with UID set.
226func NewUIDPreconditions(uid string) *Preconditions {
227 u := types.UID(uid)
228 return &Preconditions{UID: &u}
229}
230
William Kurkiandaa6bb22019-03-07 12:26:28 -0500231// NewRVDeletionPrecondition returns a DeleteOptions with a ResourceVersion precondition set.
232func NewRVDeletionPrecondition(rv string) *DeleteOptions {
233 p := Preconditions{ResourceVersion: &rv}
234 return &DeleteOptions{Preconditions: &p}
235}
236
sslobodrd046be82019-01-16 10:02:22 -0500237// HasObjectMetaSystemFieldValues returns true if fields that are managed by the system on ObjectMeta have values.
238func HasObjectMetaSystemFieldValues(meta Object) bool {
239 return !meta.GetCreationTimestamp().Time.IsZero() ||
240 len(meta.GetUID()) != 0
241}
242
243// ResetObjectMetaForStatus forces the meta fields for a status update to match the meta fields
244// for a pre-existing object. This is opt-in for new objects with Status subresource.
245func ResetObjectMetaForStatus(meta, existingMeta Object) {
246 meta.SetDeletionTimestamp(existingMeta.GetDeletionTimestamp())
247 meta.SetGeneration(existingMeta.GetGeneration())
248 meta.SetSelfLink(existingMeta.GetSelfLink())
249 meta.SetLabels(existingMeta.GetLabels())
250 meta.SetAnnotations(existingMeta.GetAnnotations())
251 meta.SetFinalizers(existingMeta.GetFinalizers())
252 meta.SetOwnerReferences(existingMeta.GetOwnerReferences())
Stephane Barbarie260a5632019-02-26 16:12:49 -0500253 meta.SetManagedFields(existingMeta.GetManagedFields())
sslobodrd046be82019-01-16 10:02:22 -0500254}
Stephane Barbarie260a5632019-02-26 16:12:49 -0500255
256// MarshalJSON implements json.Marshaler
257func (f Fields) MarshalJSON() ([]byte, error) {
258 return json.Marshal(&f.Map)
259}
260
261// UnmarshalJSON implements json.Unmarshaler
262func (f *Fields) UnmarshalJSON(b []byte) error {
263 return json.Unmarshal(b, &f.Map)
264}
265
266var _ json.Marshaler = Fields{}
267var _ json.Unmarshaler = &Fields{}