-
Notifications
You must be signed in to change notification settings - Fork 293
/
names.go
110 lines (94 loc) · 3.12 KB
/
names.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package k8s
import (
"fmt"
"strings"
"k8s.io/apimachinery/pkg/runtime/schema"
)
const fmtduplicateYAMLDetectedError = "Duplicate YAML Entity: %s has been detected across one or more resources. Only one specification per entity can be applied to the cluster; to ensure expected behavior, remove the duplicate specifications."
func DuplicateYAMLDetectedError(duplicatedYaml string) string {
return fmt.Sprintf(fmtduplicateYAMLDetectedError, duplicatedYaml)
}
func UniqueNames(entities []K8sEntity, minComponents int) []string {
meta := make([]EntityMeta, len(entities))
for i := range entities {
meta[i] = entities[i]
}
return UniqueNamesMeta(meta, minComponents)
}
// Calculates names for workloads by using the shortest uniquely matching identifiers
func UniqueNamesMeta(es []EntityMeta, minComponents int) []string {
ret := make([]string, len(es))
// how many resources potentially map to a given name
counts := make(map[string]int)
// count how many entities want each potential name
for _, e := range es {
for _, name := range potentialNames(e, minComponents) {
counts[name]++
}
}
// for each entity, take the shortest name that is uniquely wanted by that entity
for i, e := range es {
names := potentialNames(e, minComponents)
for _, name := range names {
if counts[name] == 1 {
ret[i] = name
break
}
}
if ret[i] == "" {
// If we hit this case, this means we have two resources with the same
// name/kind/namespace/group This usually means the user is trying to
// deploy the same resource twice. Kubernetes will not treat these as
// unique.
//
// Ideally, we should use the k8s object index to remove these before they
// get to this point. This only happens if the user has specified
// k8s_yaml(allow_duplicates).
//
// But for now, append the index to the name to make it unique
ret[i] = fmt.Sprintf("%s:%d", names[len(names)-1], i)
}
}
return ret
}
// FragmentsToEntities maps all possible fragments (e.g. foo, foo:secret, foo:secret:default) to the k8s entity or entities that they correspond to
func FragmentsToEntities(es []K8sEntity) map[string][]K8sEntity {
ret := make(map[string][]K8sEntity, len(es))
for _, e := range es {
names := potentialNames(e, 1)
for _, name := range names {
if a, ok := ret[name]; ok {
ret[name] = append(a, e)
} else {
ret[name] = []K8sEntity{e}
}
}
}
return ret
}
// returns a list of potential names, in order of preference
func potentialNames(e EntityMeta, minComponents int) []string {
gvk := e.GVK()
// Empty string is synonymous with the core group
// Poorly documented, but check it out here https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes
group := gvk.Group
if group == "" {
group = "core"
}
components := []string{
e.Name(),
gvk.Kind,
e.Namespace().String(),
group,
}
var ret []string
for i := minComponents - 1; i < len(components); i++ {
ret = append(ret, strings.ToLower(SelectorStringFromParts(components[:i+1])))
}
return ret
}
type EntityMeta interface {
Name() string
Namespace() Namespace
GVK() schema.GroupVersionKind
}