-
Notifications
You must be signed in to change notification settings - Fork 19
/
component_key.go
175 lines (155 loc) · 6.31 KB
/
component_key.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package resolve
import (
"github.com/Aptomi/aptomi/pkg/lang"
"strings"
)
// componentInstanceKeySeparator is a separator between strings in ComponentInstanceKey
const componentInstanceKeySeparator = "#"
// componentUnresolvedName is placeholder for unresolved entries
const componentUnresolvedName = "unknown"
// componentRootName is a name of component for service entry (which in turn consists of components)
const componentRootName = "root"
// ComponentInstanceKey is a key for component instance. During policy resolution every component instance gets
// assigned a unique string key. It's important to form those keys correctly, so that we can make actual comparison
// of actual state (components with their keys) and desired state (components with their keys).
//
// Currently, component keys are formed from multiple parameters as follows.
// Cluster gets included as a part of the key (components running on different clusters must have different keys).
// Namespace gets included as a part of the key (components from different namespaces must have different keys).
// Contract, Context (with allocation keys), Service get included as a part of the key (Service must be within the same namespace as Contract).
// ComponentName gets included as a part of the key. For service-level component instances, ComponentName is
// set to componentRootName, while for all component instances within a service an actual Component.Name is used.
type ComponentInstanceKey struct {
// cached version of component key
key string
// required fields
ClusterName string // mandatory
Namespace string // determined from the contract
ContractName string // mandatory
ContextName string // mandatory
ContextNameWithKeys string // calculated
ServiceName string // determined from the context (included into key for readability)
ComponentName string // component name
}
// NewComponentInstanceKey creates a new ComponentInstanceKey
func NewComponentInstanceKey(cluster *lang.Cluster, contract *lang.Contract, context *lang.Context, allocationsKeysResolved []string, service *lang.Service, component *lang.ServiceComponent) *ComponentInstanceKey {
contextName := getContextNameUnsafe(context)
contextNameWithKeys := getContextNameWithKeys(contextName, allocationsKeysResolved)
return &ComponentInstanceKey{
ClusterName: getClusterNameUnsafe(cluster),
Namespace: getContractNamespaceUnsafe(contract),
ContractName: getContractNameUnsafe(contract),
ContextName: contextName,
ContextNameWithKeys: contextNameWithKeys,
ServiceName: getServiceNameUnsafe(service),
ComponentName: getComponentNameUnsafe(component),
}
}
// MakeCopy creates a copy of ComponentInstanceKey
func (cik *ComponentInstanceKey) MakeCopy() *ComponentInstanceKey {
return &ComponentInstanceKey{
ClusterName: cik.ClusterName,
Namespace: cik.Namespace,
ContractName: cik.ContractName,
ContextName: cik.ContextName,
ContextNameWithKeys: cik.ContextNameWithKeys,
ComponentName: cik.ComponentName,
}
}
// IsService returns 'true' if it's a contract instance key and we can't go up anymore. And it will return 'false' if it's a component instance key
func (cik *ComponentInstanceKey) IsService() bool {
return cik.ComponentName == componentRootName
}
// IsComponent returns 'true' if it's a component instance key and we can go up to the corresponding service. And it will return 'false' if it's a service instance key
func (cik *ComponentInstanceKey) IsComponent() bool {
return cik.ComponentName != componentRootName
}
// GetParentServiceKey returns a key for the parent service, replacing componentName with componentRootName
func (cik *ComponentInstanceKey) GetParentServiceKey() *ComponentInstanceKey {
if cik.ComponentName == componentRootName {
return cik
}
serviceCik := cik.MakeCopy()
serviceCik.ComponentName = componentRootName
return serviceCik
}
// GetKey returns a string key
func (cik ComponentInstanceKey) GetKey() string {
if cik.key == "" {
cik.key = strings.Join(
[]string{
cik.ClusterName,
cik.Namespace,
cik.ContractName,
cik.ContextNameWithKeys,
cik.ComponentName,
}, componentInstanceKeySeparator)
}
return cik.key
}
// GetDeployName returns a string that could be used as name for deployment inside the cluster
func (cik ComponentInstanceKey) GetDeployName() string {
return strings.Join(
[]string{
cik.Namespace,
cik.ContractName,
cik.ContextNameWithKeys,
cik.ComponentName,
}, componentInstanceKeySeparator)
}
// If cluster has not been resolved yet and we need a key, generate one
// Otherwise use cluster name
func getClusterNameUnsafe(cluster *lang.Cluster) string {
if cluster == nil {
return componentUnresolvedName
}
return cluster.Name
}
// If contract has not been resolved yet and we need a key, generate one
// Otherwise use contract name
func getContractNameUnsafe(contract *lang.Contract) string {
if contract == nil {
return componentUnresolvedName
}
return contract.Name
}
// If contract has not been resolved yet and we need a key, generate one
// Otherwise use contract namespace
func getContractNamespaceUnsafe(contract *lang.Contract) string {
if contract == nil {
return componentUnresolvedName
}
return contract.Namespace
}
// If context has not been resolved yet and we need a key, generate one
// Otherwise use context name
func getContextNameUnsafe(context *lang.Context) string {
if context == nil {
return componentUnresolvedName
}
return context.Name
}
// If service has not been resolved yet and we need a key, generate one
// Otherwise use service name
func getServiceNameUnsafe(service *lang.Service) string {
if service == nil {
return componentUnresolvedName
}
return service.Name
}
// If component has not been resolved yet and we need a key, generate one
// Otherwise use component name
func getComponentNameUnsafe(component *lang.ServiceComponent) string {
if component == nil {
return componentRootName
}
return component.Name
}
// Returns context name combined with allocation keys
func getContextNameWithKeys(contextName string, allocationKeysResolved []string) string {
result := contextName
if len(allocationKeysResolved) > 0 {
result += componentInstanceKeySeparator + strings.Join(allocationKeysResolved, componentInstanceKeySeparator)
}
return result
}