istio
169 строк · 6.0 Кб
1// Copyright Istio Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package serviceentry
16
17import (
18"k8s.io/apimachinery/pkg/types"
19
20"istio.io/istio/pilot/pkg/model"
21"istio.io/istio/pkg/util/sets"
22)
23
24type hostPort struct {
25host instancesKey
26port int
27}
28
29// stores all the service instances from SE, WLE and pods
30type serviceInstancesStore struct {
31ip2instance map[string][]*model.ServiceInstance
32// service instances by hostname -> config
33instances map[instancesKey]map[configKey][]*model.ServiceInstance
34// instances only for serviceentry
35instancesBySE map[types.NamespacedName]map[configKey][]*model.ServiceInstance
36// instancesByHostAndPort tells whether the host has instances.
37// This is used to validate that we only have one instance for DNS_ROUNDROBIN_LB.
38instancesByHostAndPort sets.Set[hostPort]
39}
40
41func (s *serviceInstancesStore) getByIP(ip string) []*model.ServiceInstance {
42return s.ip2instance[ip]
43}
44
45func (s *serviceInstancesStore) getAll() []*model.ServiceInstance {
46all := []*model.ServiceInstance{}
47for _, instances := range s.ip2instance {
48all = append(all, instances...)
49}
50return all
51}
52
53func (s *serviceInstancesStore) getByKey(key instancesKey) []*model.ServiceInstance {
54all := []*model.ServiceInstance{}
55for _, instances := range s.instances[key] {
56all = append(all, instances...)
57}
58return all
59}
60
61// deleteInstanceKeys deletes all instances with the given configKey and instanceKey
62// Note: as a convenience, this takes a []ServiceInstance instead of []instanceKey, as most callers have this format
63// However, this function only operates on the instance keys
64func (s *serviceInstancesStore) deleteInstanceKeys(key configKey, instances []*model.ServiceInstance) {
65for _, i := range instances {
66ikey := makeInstanceKey(i)
67s.instancesByHostAndPort.Delete(hostPort{ikey, i.ServicePort.Port})
68oldInstances := s.instances[ikey][key]
69delete(s.instances[ikey], key)
70if len(s.instances[ikey]) == 0 {
71delete(s.instances, ikey)
72}
73delete(s.ip2instance, i.Endpoint.Address)
74// Cleanup stale IPs, if the IPs changed
75for _, oi := range oldInstances {
76s.instancesByHostAndPort.Delete(hostPort{ikey, oi.ServicePort.Port})
77delete(s.ip2instance, oi.Endpoint.Address)
78}
79}
80}
81
82// addInstances add the instances to the store.
83func (s *serviceInstancesStore) addInstances(key configKey, instances []*model.ServiceInstance) {
84for _, instance := range instances {
85ikey := makeInstanceKey(instance)
86hostPort := hostPort{ikey, instance.ServicePort.Port}
87// For DNSRoundRobinLB resolution type, check if service instances already exist and do not add
88// if it already exist. This can happen if two Service Entries are created with same host name,
89// resolution as DNS_ROUND_ROBIN and with same/different endpoints.
90if instance.Service.Resolution == model.DNSRoundRobinLB &&
91s.instancesByHostAndPort.Contains(hostPort) {
92log.Debugf("skipping service %s from service entry %s with DnsRoundRobinLB. A service entry with the same host "+
93"already exists. Only one locality lb end point is allowed for DnsRoundRobinLB services.",
94ikey.hostname, key.name+"/"+key.namespace)
95continue
96}
97if _, f := s.instances[ikey]; !f {
98s.instances[ikey] = map[configKey][]*model.ServiceInstance{}
99}
100s.instancesByHostAndPort.Insert(hostPort)
101s.instances[ikey][key] = append(s.instances[ikey][key], instance)
102if instance.Endpoint.Address != "" {
103s.ip2instance[instance.Endpoint.Address] = append(s.ip2instance[instance.Endpoint.Address], instance)
104}
105}
106}
107
108func (s *serviceInstancesStore) updateInstances(key configKey, instances []*model.ServiceInstance) {
109// first delete
110s.deleteInstanceKeys(key, instances)
111
112// second add
113s.addInstances(key, instances)
114}
115
116func (s *serviceInstancesStore) getServiceEntryInstances(key types.NamespacedName) map[configKey][]*model.ServiceInstance {
117return s.instancesBySE[key]
118}
119
120func (s *serviceInstancesStore) updateServiceEntryInstances(key types.NamespacedName, instances map[configKey][]*model.ServiceInstance) {
121s.instancesBySE[key] = instances
122}
123
124func (s *serviceInstancesStore) updateServiceEntryInstancesPerConfig(key types.NamespacedName, cKey configKey, instances []*model.ServiceInstance) {
125if s.instancesBySE[key] == nil {
126s.instancesBySE[key] = map[configKey][]*model.ServiceInstance{}
127}
128s.instancesBySE[key][cKey] = instances
129}
130
131func (s *serviceInstancesStore) deleteServiceEntryInstances(key types.NamespacedName, cKey configKey) {
132delete(s.instancesBySE[key], cKey)
133if len(s.instancesBySE[key]) == 0 {
134delete(s.instancesBySE, key)
135}
136}
137
138func (s *serviceInstancesStore) deleteAllServiceEntryInstances(key types.NamespacedName) {
139delete(s.instancesBySE, key)
140}
141
142// stores all the services converted from serviceEntries
143type serviceStore struct {
144// services keeps track of all services - mainly used to return from Services() to avoid reconversion.
145servicesBySE map[types.NamespacedName][]*model.Service
146allocateNeeded bool
147}
148
149// getAllServices return all the services.
150func (s *serviceStore) getAllServices() []*model.Service {
151var out []*model.Service
152for _, svcs := range s.servicesBySE {
153out = append(out, svcs...)
154}
155return model.SortServicesByCreationTime(out)
156}
157
158func (s *serviceStore) getServices(key types.NamespacedName) []*model.Service {
159return s.servicesBySE[key]
160}
161
162func (s *serviceStore) deleteServices(key types.NamespacedName) {
163delete(s.servicesBySE, key)
164}
165
166func (s *serviceStore) updateServices(key types.NamespacedName, services []*model.Service) {
167s.servicesBySE[key] = services
168s.allocateNeeded = true
169}
170