blob: d9eeb4f919669bcdb8191464822be7b42fbff090 [file] [log] [blame]
Matteo Scandoloa4285862020-12-01 18:10:10 -08001/*
2Copyright 2014 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 labels
18
19import (
20 "fmt"
21 "sort"
22 "strings"
23)
24
25// Labels allows you to present labels independently from their storage.
26type Labels interface {
27 // Has returns whether the provided label exists.
28 Has(label string) (exists bool)
29
30 // Get returns the value for the provided label.
31 Get(label string) (value string)
32}
33
34// Set is a map of label:value. It implements Labels.
35type Set map[string]string
36
37// String returns all labels listed as a human readable string.
38// Conveniently, exactly the format that ParseSelector takes.
39func (ls Set) String() string {
40 selector := make([]string, 0, len(ls))
41 for key, value := range ls {
42 selector = append(selector, key+"="+value)
43 }
44 // Sort for determinism.
45 sort.StringSlice(selector).Sort()
46 return strings.Join(selector, ",")
47}
48
49// Has returns whether the provided label exists in the map.
50func (ls Set) Has(label string) bool {
51 _, exists := ls[label]
52 return exists
53}
54
55// Get returns the value in the map for the provided label.
56func (ls Set) Get(label string) string {
57 return ls[label]
58}
59
60// AsSelector converts labels into a selectors. It does not
61// perform any validation, which means the server will reject
62// the request if the Set contains invalid values.
63func (ls Set) AsSelector() Selector {
64 return SelectorFromSet(ls)
65}
66
67// AsValidatedSelector converts labels into a selectors.
68// The Set is validated client-side, which allows to catch errors early.
69func (ls Set) AsValidatedSelector() (Selector, error) {
70 return ValidatedSelectorFromSet(ls)
71}
72
73// AsSelectorPreValidated converts labels into a selector, but
74// assumes that labels are already validated and thus doesn't
75// perform any validation.
76// According to our measurements this is significantly faster
77// in codepaths that matter at high scale.
78func (ls Set) AsSelectorPreValidated() Selector {
79 return SelectorFromValidatedSet(ls)
80}
81
82// FormatLabels convert label map into plain string
83func FormatLabels(labelMap map[string]string) string {
84 l := Set(labelMap).String()
85 if l == "" {
86 l = "<none>"
87 }
88 return l
89}
90
91// Conflicts takes 2 maps and returns true if there a key match between
92// the maps but the value doesn't match, and returns false in other cases
93func Conflicts(labels1, labels2 Set) bool {
94 small := labels1
95 big := labels2
96 if len(labels2) < len(labels1) {
97 small = labels2
98 big = labels1
99 }
100
101 for k, v := range small {
102 if val, match := big[k]; match {
103 if val != v {
104 return true
105 }
106 }
107 }
108
109 return false
110}
111
112// Merge combines given maps, and does not check for any conflicts
113// between the maps. In case of conflicts, second map (labels2) wins
114func Merge(labels1, labels2 Set) Set {
115 mergedMap := Set{}
116
117 for k, v := range labels1 {
118 mergedMap[k] = v
119 }
120 for k, v := range labels2 {
121 mergedMap[k] = v
122 }
123 return mergedMap
124}
125
126// Equals returns true if the given maps are equal
127func Equals(labels1, labels2 Set) bool {
128 if len(labels1) != len(labels2) {
129 return false
130 }
131
132 for k, v := range labels1 {
133 value, ok := labels2[k]
134 if !ok {
135 return false
136 }
137 if value != v {
138 return false
139 }
140 }
141 return true
142}
143
144// AreLabelsInWhiteList verifies if the provided label list
145// is in the provided whitelist and returns true, otherwise false.
146func AreLabelsInWhiteList(labels, whitelist Set) bool {
147 if len(whitelist) == 0 {
148 return true
149 }
150
151 for k, v := range labels {
152 value, ok := whitelist[k]
153 if !ok {
154 return false
155 }
156 if value != v {
157 return false
158 }
159 }
160 return true
161}
162
163// ConvertSelectorToLabelsMap converts selector string to labels map
164// and validates keys and values
165func ConvertSelectorToLabelsMap(selector string) (Set, error) {
166 labelsMap := Set{}
167
168 if len(selector) == 0 {
169 return labelsMap, nil
170 }
171
172 labels := strings.Split(selector, ",")
173 for _, label := range labels {
174 l := strings.Split(label, "=")
175 if len(l) != 2 {
176 return labelsMap, fmt.Errorf("invalid selector: %s", l)
177 }
178 key := strings.TrimSpace(l[0])
179 if err := validateLabelKey(key); err != nil {
180 return labelsMap, err
181 }
182 value := strings.TrimSpace(l[1])
183 if err := validateLabelValue(key, value); err != nil {
184 return labelsMap, err
185 }
186 labelsMap[key] = value
187 }
188 return labelsMap, nil
189}