1 package labels
2
3 import (
4 "errors"
5 "regexp"
6 "strings"
7 "unicode"
8
9 dfutil "github.com/devfile/library/v2/pkg/util"
10 k8slabels "k8s.io/apimachinery/pkg/labels"
11 "k8s.io/apimachinery/pkg/util/validation"
12 "k8s.io/klog"
13
14 "github.com/redhat-developer/odo/pkg/version"
15 )
16
17 var _replacementMap = map[string]string{
18 ".": "dot",
19 "#": "sharp",
20 }
21
22 var (
23 _regexpInvalidCharacters = regexp.MustCompile(`[^a-zA-Z0-9._-]`)
24 _regexpStartingWithAlphanumeric = regexp.MustCompile(`^[a-z0-9A-Z]`)
25 _regexpEndingWithAlphanumeric = regexp.MustCompile(`[a-z0-9A-Z]$`)
26 )
27
28
29
30
31
32 func GetLabels(componentName string, applicationName string, runtime string, mode string, isPartOfComponent bool) map[string]string {
33 labels := getLabels(componentName, applicationName, mode, true, isPartOfComponent)
34 if runtime != "" {
35
36 labels[openshiftRunTimeLabel] = strings.ToLower(sanitizeLabelValue(openshiftRunTimeLabel, runtime))
37 }
38 return labels
39 }
40
41
42
43
44
45
46
47
48
49
50
51
52 func sanitizeLabelValue(key, value string) string {
53 errs := validation.IsValidLabelValue(value)
54 if len(errs) == 0 {
55 return value
56 }
57
58 klog.V(4).Infof("invalid value for label %q: %q => sanitizing it: %v", key, value, strings.Join(errs, "; "))
59
60
61 if v, ok := _replacementMap[value]; ok {
62 return v
63 }
64
65
66 value = replaceAllLeadingOrTrailingInvalidValues(value)
67
68
69 value = _regexpInvalidCharacters.ReplaceAllString(value, "-")
70
71
72 if len(value) > validation.LabelValueMaxLength {
73 value = dfutil.TruncateString(value, validation.LabelValueMaxLength)
74 }
75
76 if errs = validation.IsValidLabelValue(value); len(errs) == 0 {
77 return value
78 }
79 return sanitizeLabelValue(key, value)
80 }
81
82 func replaceAllLeadingOrTrailingInvalidValues(value string) string {
83 if value == "" {
84 return ""
85 }
86
87 isAllCaseMatchingPredicate := func(p func(rune) bool, s string) bool {
88 for _, r := range s {
89 if !p(r) && unicode.IsLetter(r) {
90 return false
91 }
92 }
93 return true
94 }
95 getLabelValueReplacement := func(v, replacement string) string {
96 if isAllCaseMatchingPredicate(unicode.IsLower, v) {
97 return strings.ToLower(replacement)
98 }
99 if isAllCaseMatchingPredicate(unicode.IsUpper, v) {
100 return strings.ToUpper(replacement)
101 }
102 return replacement
103 }
104
105 if !_regexpStartingWithAlphanumeric.MatchString(value) {
106 vAfterFirstChar := value[1:]
107 var isPrefixReplaced bool
108 for k, val := range _replacementMap {
109 if strings.HasPrefix(value, k) {
110 value = getLabelValueReplacement(vAfterFirstChar, val) + vAfterFirstChar
111 isPrefixReplaced = true
112 break
113 }
114 }
115 if !isPrefixReplaced {
116 value = vAfterFirstChar
117 }
118 if value == "" {
119 return value
120 }
121 }
122 if !_regexpEndingWithAlphanumeric.MatchString(value) {
123 vBeforeLastChar := value[:len(value)-1]
124 var isSuffixReplaced bool
125 for k, val := range _replacementMap {
126 if strings.HasSuffix(value, k) {
127 value = vBeforeLastChar + getLabelValueReplacement(vBeforeLastChar, val)
128 isSuffixReplaced = true
129 break
130 }
131 }
132 if !isSuffixReplaced {
133 value = vBeforeLastChar
134 }
135 }
136 return value
137 }
138
139
140 func AddStorageInfo(labels map[string]string, storageName string, isSourceVolume bool) {
141 labels[kubernetesStorageNameLabel] = storageName
142 labels[componentLabel] = labels[kubernetesInstanceLabel]
143 labels[devfileStorageLabel] = storageName
144 if isSourceVolume {
145 labels[sourcePVCLabel] = storageName
146 }
147 }
148
149 func GetStorageName(labels map[string]string) string {
150 return labels[kubernetesStorageNameLabel]
151 }
152
153 func GetDevfileStorageName(labels map[string]string) string {
154 return labels[devfileStorageLabel]
155 }
156
157 func GetComponentName(labels map[string]string) string {
158 return labels[kubernetesInstanceLabel]
159 }
160
161 func GetAppName(labels map[string]string) string {
162 return labels[kubernetesPartOfLabel]
163 }
164
165 func GetManagedBy(labels map[string]string) string {
166 return labels[kubernetesManagedByLabel]
167 }
168
169 func GetManagedByVersion(labels map[string]string) string {
170 return labels[kubernetesManagedByVersionLabel]
171 }
172
173 func IsManagedByOdo(labels map[string]string) bool {
174 return labels[kubernetesManagedByLabel] == odoManager
175 }
176
177 func GetMode(labels map[string]string) string {
178 return labels[odoModeLabel]
179 }
180
181
182
183 func IsProjectTypeSetInAnnotations(annotations map[string]string) bool {
184 _, ok := annotations[odoProjectTypeAnnotation]
185 return ok
186 }
187
188 func GetProjectType(labels map[string]string, annotations map[string]string) (string, error) {
189
190
191 if typ, ok := annotations[odoProjectTypeAnnotation]; ok {
192 return typ, nil
193 }
194 if typ, ok := labels[odoProjectTypeAnnotation]; ok {
195 return typ, nil
196 }
197 return "", errors.New("component type not found in labels or annotations")
198 }
199
200 func SetProjectType(annotations map[string]string, value string) {
201 annotations[odoProjectTypeAnnotation] = value
202 }
203
204 func AddCommonAnnotations(annotations map[string]string) {
205
206
207 annotations["alpha.image.policy.openshift.io/resolve-names"] = "*"
208 }
209
210
211
212
213 func GetSelector(componentName string, applicationName string, mode string, isPartOfComponent bool) string {
214 labels := getLabels(componentName, applicationName, mode, false, isPartOfComponent)
215 return labels.String()
216 }
217
218 func GetNameSelector(componentName string) string {
219 labels := k8slabels.Set{
220 kubernetesInstanceLabel: componentName,
221 }
222 return labels.String()
223 }
224
225
226
227 func IsCoreComponent(labels map[string]string) bool {
228 if _, ok := labels[componentLabel]; ok {
229 return true
230 }
231 return false
232 }
233
234
235
236
237
238
239
240 func getLabels(componentName string, applicationName string, mode string, additional bool, isPartOfComponent bool) k8slabels.Set {
241 labels := getApplicationLabels(applicationName, additional)
242 labels[kubernetesInstanceLabel] = componentName
243 if mode != ComponentAnyMode {
244 labels[odoModeLabel] = mode
245 }
246 if isPartOfComponent {
247 labels[componentLabel] = componentName
248 }
249 return labels
250 }
251
252
253
254
255
256 func getApplicationLabels(application string, additional bool) k8slabels.Set {
257 labels := k8slabels.Set{
258 kubernetesPartOfLabel: application,
259 kubernetesManagedByLabel: odoManager,
260 }
261 if additional {
262 labels[appLabel] = application
263 labels[kubernetesManagedByVersionLabel] = version.VERSION
264 }
265 return labels
266 }
267
View as plain text