-
Notifications
You must be signed in to change notification settings - Fork 359
Expand file tree
/
Copy pathdestinations.go
More file actions
313 lines (279 loc) · 10.3 KB
/
destinations.go
File metadata and controls
313 lines (279 loc) · 10.3 KB
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
package zoneproxy
import (
"reflect"
"slices"
mesh_proto "github.com/kumahq/kuma/v2/api/mesh/v1alpha1"
"github.com/kumahq/kuma/v2/pkg/core/kri"
core_resources "github.com/kumahq/kuma/v2/pkg/core/resources/apis/core"
"github.com/kumahq/kuma/v2/pkg/core/resources/apis/core/destinationname"
core_mesh "github.com/kumahq/kuma/v2/pkg/core/resources/apis/mesh"
meshservice_api "github.com/kumahq/kuma/v2/pkg/core/resources/apis/meshservice/api/v1alpha1"
core_model "github.com/kumahq/kuma/v2/pkg/core/resources/model"
"github.com/kumahq/kuma/v2/pkg/dns"
"github.com/kumahq/kuma/v2/pkg/plugins/policies/core/rules/resolve"
meshhttproute_api "github.com/kumahq/kuma/v2/pkg/plugins/policies/meshhttproute/api/v1alpha1"
meshtcproute_api "github.com/kumahq/kuma/v2/pkg/plugins/policies/meshtcproute/api/v1alpha1"
"github.com/kumahq/kuma/v2/pkg/util/pointer"
util_slices "github.com/kumahq/kuma/v2/pkg/util/slices"
xds_context "github.com/kumahq/kuma/v2/pkg/xds/context"
envoy_tags "github.com/kumahq/kuma/v2/pkg/xds/envoy/tags"
"github.com/kumahq/kuma/v2/pkg/xds/envoy/tls"
)
type MeshDestinations struct {
KumaIoServices map[string][]envoy_tags.Tags
BackendRefs []BackendRefDestination
}
type BackendRefDestination struct {
resolve.ResolvedBackendRef
Mesh string
SNI string
LegacyServiceName string
}
func BuildMeshDestinations(
availableServices []*mesh_proto.ZoneIngress_AvailableService, // available services for a single mesh
systemNamespace string,
resources xds_context.Resources,
realResourceLists ...core_resources.DestinationList,
) MeshDestinations {
return MeshDestinations{
KumaIoServices: buildKumaIoServiceDestinations(availableServices, resources),
BackendRefs: buildRealResourceDestinations(
util_slices.FlatMap(realResourceLists, core_resources.DestinationList.GetDestinations),
systemNamespace,
),
}
}
func buildRealResourceDestinations(destinations []core_resources.Destination, systemNS string) []BackendRefDestination {
return util_slices.FlatMap(destinations, func(dest core_resources.Destination) []BackendRefDestination {
origin := kri.From(dest)
mesh := dest.GetMeta().GetMesh()
var rName string
switch r := any(dest).(type) {
case *meshservice_api.MeshServiceResource:
rName = r.SNIName(systemNS)
default:
rName = core_model.GetDisplayName(dest.GetMeta())
}
return util_slices.Map(dest.GetPorts(), func(port core_resources.Port) BackendRefDestination {
return BackendRefDestination{
Mesh: mesh,
SNI: tls.SNIForResource(rName, mesh, origin.ResourceType, port.GetValue(), nil),
LegacyServiceName: destinationname.ResolveLegacyFromDestination(dest, port),
ResolvedBackendRef: resolve.ResolvedBackendRef{
Ref: &resolve.RealResourceBackendRef{
Resource: kri.WithSectionName(origin, port.GetName()),
Origin: origin,
Weight: 1,
},
},
}
})
})
}
func buildKumaIoServiceDestinations(
availableServices []*mesh_proto.ZoneIngress_AvailableService, // available services for a single mesh
res xds_context.Resources,
) map[string][]envoy_tags.Tags {
destForMesh := map[string][]envoy_tags.Tags{}
trafficRoutes := res.TrafficRoutes().Items
addTrafficRouteDestinations(trafficRoutes, destForMesh)
meshHTTPRoutes := res.ListOrEmpty(meshhttproute_api.MeshHTTPRouteType).(*meshhttproute_api.MeshHTTPRouteResourceList).Items
meshTCPRoutes := res.ListOrEmpty(meshtcproute_api.MeshTCPRouteType).(*meshtcproute_api.MeshTCPRouteResourceList).Items
addMeshHTTPRouteDestinations(trafficRoutes, meshHTTPRoutes, destForMesh)
addMeshTCPRouteDestinations(trafficRoutes, meshTCPRoutes, destForMesh)
addGatewayRouteDestinations(res.GatewayRoutes().Items, destForMesh)
addMeshGatewayDestinations(res.MeshGateways().Items, destForMesh)
addVirtualOutboundDestinations(res.VirtualOutbounds().Items, availableServices, destForMesh)
return destForMesh
}
func addMeshGatewayDestinations(
meshGateways []*core_mesh.MeshGatewayResource,
destinations map[string][]envoy_tags.Tags,
) {
for _, meshGateway := range meshGateways {
for _, selector := range meshGateway.Selectors() {
addMeshGatewayListenersDestinations(
meshGateway.Spec,
selector.GetMatch(),
destinations,
)
}
}
}
func addMeshGatewayListenersDestinations(
meshGateway *mesh_proto.MeshGateway,
matchTags map[string]string,
destinations map[string][]envoy_tags.Tags,
) {
service := matchTags[mesh_proto.ServiceTag]
for _, listener := range meshGateway.GetConf().GetListeners() {
if !listener.CrossMesh {
continue
}
destinations[service] = append(
destinations[service],
mesh_proto.Merge(
meshGateway.GetTags(),
matchTags,
listener.GetTags(),
),
)
}
}
func addGatewayRouteDestinations(
gatewayRoutes []*core_mesh.MeshGatewayRouteResource,
destinations map[string][]envoy_tags.Tags,
) {
var backends []*mesh_proto.MeshGatewayRoute_Backend
for _, route := range gatewayRoutes {
for _, rule := range route.Spec.GetConf().GetHttp().GetRules() {
backends = append(backends, rule.Backends...)
}
for _, rule := range route.Spec.GetConf().GetTcp().GetRules() {
backends = append(backends, rule.Backends...)
}
}
for _, backend := range backends {
addDestination(backend.Destination, destinations)
}
}
func addTrafficRouteDestinations(
policies []*core_mesh.TrafficRouteResource,
destinations map[string][]envoy_tags.Tags,
) {
for _, policy := range policies {
for _, split := range policy.Spec.Conf.GetSplitWithDestination() {
addDestination(split.Destination, destinations)
}
for _, http := range policy.Spec.Conf.Http {
for _, split := range http.GetSplitWithDestination() {
addDestination(split.Destination, destinations)
}
}
}
}
func addMeshHTTPRouteDestinations(
trafficRoutes []*core_mesh.TrafficRouteResource,
policies []*meshhttproute_api.MeshHTTPRouteResource,
destinations map[string][]envoy_tags.Tags,
) {
if len(trafficRoutes) == 0 {
addTrafficFlowByDefaultDestination(destinations)
}
// Note that we're not merging these resources, but that's OK because the
// set of destinations after merging is a subset of the set we get here by
// iterating through them.
for _, policy := range policies {
for _, to := range pointer.Deref(policy.Spec.To) {
if toTags, ok := envoy_tags.FromLegacyTargetRef(to.TargetRef); ok {
addMeshHTTPRouteToDestinations(to.Rules, toTags, destinations)
}
}
}
}
func addMeshTCPRouteDestinations(
trafficRoutes []*core_mesh.TrafficRouteResource,
policies []*meshtcproute_api.MeshTCPRouteResource,
destinations map[string][]envoy_tags.Tags,
) {
if len(trafficRoutes) == 0 {
addTrafficFlowByDefaultDestination(destinations)
}
// Note that we're not merging these resources, but that's OK because the
// set of destinations after merging is a subset of the set we get here by
// iterating through them.
for _, policy := range policies {
for _, to := range pointer.Deref(policy.Spec.To) {
if toTags, ok := envoy_tags.FromLegacyTargetRef(to.TargetRef); ok {
addMeshTCPRouteToDestinations(to.Rules, toTags, destinations)
}
}
}
}
func addMeshHTTPRouteToDestinations(
rules []meshhttproute_api.Rule,
toTags envoy_tags.Tags,
destinations map[string][]envoy_tags.Tags,
) {
for _, rule := range rules {
if rule.Default.BackendRefs == nil {
addDestination(toTags, destinations)
continue
}
for _, backendRef := range pointer.Deref(rule.Default.BackendRefs) {
if tags, ok := envoy_tags.FromLegacyTargetRef(backendRef.TargetRef); ok {
addDestination(tags, destinations)
}
}
}
}
func addMeshTCPRouteToDestinations(
rules []meshtcproute_api.Rule,
toTags envoy_tags.Tags,
destinations map[string][]envoy_tags.Tags,
) {
for _, rule := range rules {
if rule.Default.BackendRefs == nil {
addDestination(toTags, destinations)
continue
}
for _, backendRef := range pointer.Deref(rule.Default.BackendRefs) {
if tags, ok := envoy_tags.FromLegacyTargetRef(backendRef.TargetRef); ok {
addDestination(tags, destinations)
}
}
}
}
func addDestination(tags map[string]string, destinations map[string][]envoy_tags.Tags) {
service := tags[mesh_proto.ServiceTag]
destinations[service] = append(destinations[service], tags)
}
// addTrafficFlowByDefaultDestinationIfMeshHTTPRoutesExist makes sure that when
// at least one MeshHTTPRoute policy exists there will be a "match all"
// destination pointing to all services (kuma.io/service:* -> kuma.io/service:*)
// This logic is necessary because of conflicting behaviors of TrafficRoute and
// MeshHTTPRoute policies. TrafficRoute expects that by default traffic doesn't
// flow, and there is necessary TrafficRoute with appropriate configuration
// to make communication between services possible. MeshHTTPRoute on the other
// hand expects the traffic to flow by default. As a result, when there is
// at least one MeshHTTPRoute policy present, traffic between services will flow
// by default, when there is none, it will flow, when appropriate TrafficRoute
// policy will exist.
func addTrafficFlowByDefaultDestination(
destinations map[string][]envoy_tags.Tags,
) {
// We need to add a destination to route any service to any instance of
// that service
matchAllTags := envoy_tags.Tags{mesh_proto.ServiceTag: mesh_proto.MatchAllTag}
matchAllDestinations := destinations[mesh_proto.MatchAllTag]
foundAllServicesDestination := slices.ContainsFunc(
matchAllDestinations,
func(tagsElem envoy_tags.Tags) bool {
return reflect.DeepEqual(tagsElem, matchAllTags)
},
)
if !foundAllServicesDestination {
matchAllDestinations = append(matchAllDestinations, matchAllTags)
}
destinations[mesh_proto.MatchAllTag] = matchAllDestinations
}
func addVirtualOutboundDestinations(
virtualOutbounds []*core_mesh.VirtualOutboundResource,
availableServices []*mesh_proto.ZoneIngress_AvailableService,
destinations map[string][]envoy_tags.Tags,
) {
// If there are no VirtualOutbounds, we are not modifying destinations
if len(virtualOutbounds) == 0 {
return
}
for _, availableService := range availableServices {
for _, matched := range dns.Match(virtualOutbounds, availableService.Tags) {
service := availableService.Tags[mesh_proto.ServiceTag]
tags := envoy_tags.Tags{}
for _, param := range matched.Spec.GetConf().GetParameters() {
tags[param.TagKey] = availableService.Tags[param.TagKey]
}
destinations[service] = append(destinations[service], tags)
}
}
}