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