istio

Форк
0
158 строк · 6.2 Кб
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

15
package gateway
16

17
import (
18
	"fmt"
19
	"sort"
20
	"strconv"
21
	"strings"
22

23
	corev1 "k8s.io/api/core/v1"
24

25
	networking "istio.io/api/networking/v1alpha3"
26
	"istio.io/istio/pilot/pkg/model"
27
	"istio.io/istio/pkg/cluster"
28
	"istio.io/istio/pkg/config/constants"
29
	"istio.io/istio/pkg/config/host"
30
	"istio.io/istio/pkg/util/sets"
31
)
32

33
// GatewayContext contains a minimal subset of push context functionality to be exposed to GatewayAPIControllers
34
type GatewayContext struct {
35
	ps      *model.PushContext
36
	cluster cluster.ID
37
}
38

39
func NewGatewayContext(ps *model.PushContext, cluster cluster.ID) GatewayContext {
40
	return GatewayContext{ps, cluster}
41
}
42

43
// ResolveGatewayInstances attempts to resolve all instances that a gateway will be exposed on.
44
// Note: this function considers *all* instances of the service; its possible those instances will not actually be properly functioning
45
// gateways, so this is not 100% accurate, but sufficient to expose intent to users.
46
// The actual configuration generation is done on a per-workload basis and will get the exact set of matched instances for that workload.
47
// Four sets are exposed:
48
// * Internal addresses (eg istio-ingressgateway.istio-system.svc.cluster.local:80).
49
// * Internal IP addresses (eg 1.2.3.4). This comes from ClusterIP.
50
// * External addresses (eg 1.2.3.4), this comes from LoadBalancer services. There may be multiple in some cases (especially multi cluster).
51
// * Pending addresses (eg istio-ingressgateway.istio-system.svc), are LoadBalancer-type services with pending external addresses.
52
// * Warnings for references that could not be resolved. These are intended to be user facing.
53
func (gc GatewayContext) ResolveGatewayInstances(
54
	namespace string,
55
	gwsvcs []string,
56
	servers []*networking.Server,
57
) (internal, internalIP, external, pending, warns []string, allUsable bool) {
58
	ports := map[int]struct{}{}
59
	for _, s := range servers {
60
		ports[int(s.Port.Number)] = struct{}{}
61
	}
62
	foundInternal := sets.New[string]()
63
	foundInternalIP := sets.New[string]()
64
	foundExternal := sets.New[string]()
65
	foundPending := sets.New[string]()
66
	warnings := []string{}
67
	foundUnusable := false
68
	log.Debugf("Resolving gateway instances for %v in namespace %s", gwsvcs, namespace)
69
	for _, g := range gwsvcs {
70
		svc, f := gc.ps.ServiceIndex.HostnameAndNamespace[host.Name(g)][namespace]
71
		if !f {
72
			otherNamespaces := []string{}
73
			for ns := range gc.ps.ServiceIndex.HostnameAndNamespace[host.Name(g)] {
74
				otherNamespaces = append(otherNamespaces, `"`+ns+`"`) // Wrap in quotes for output
75
			}
76
			if len(otherNamespaces) > 0 {
77
				sort.Strings(otherNamespaces)
78
				warnings = append(warnings, fmt.Sprintf("hostname %q not found in namespace %q, but it was found in namespace(s) %v",
79
					g, namespace, strings.Join(otherNamespaces, ", ")))
80
			} else {
81
				warnings = append(warnings, fmt.Sprintf("hostname %q not found", g))
82
			}
83
			foundUnusable = true
84
			continue
85
		}
86
		svcKey := svc.Key()
87
		for port := range ports {
88
			instances := gc.ps.ServiceEndpointsByPort(svc, port, nil)
89
			if len(instances) > 0 {
90
				foundInternal.Insert(fmt.Sprintf("%s:%d", g, port))
91
				foundInternalIP.InsertAll(svc.GetAddresses(&model.Proxy{Metadata: &model.NodeMetadata{ClusterID: gc.cluster}})...)
92
				if svc.Attributes.ClusterExternalAddresses.Len() > 0 {
93
					// Fetch external IPs from all clusters
94
					svc.Attributes.ClusterExternalAddresses.ForEach(func(c cluster.ID, externalIPs []string) {
95
						foundExternal.InsertAll(externalIPs...)
96
					})
97
				} else if corev1.ServiceType(svc.Attributes.Type) == corev1.ServiceTypeLoadBalancer {
98
					if !foundPending.Contains(g) {
99
						warnings = append(warnings, fmt.Sprintf("address pending for hostname %q", g))
100
						foundPending.Insert(g)
101
					}
102
				}
103
			} else {
104
				instancesByPort := gc.ps.ServiceEndpoints(svcKey)
105
				if instancesEmpty(instancesByPort) {
106
					warnings = append(warnings, fmt.Sprintf("no instances found for hostname %q", g))
107
				} else {
108
					hintPort := sets.New[string]()
109
					for servicePort, instances := range instancesByPort {
110
						for _, i := range instances {
111
							if i.EndpointPort == uint32(port) {
112
								hintPort.Insert(strconv.Itoa(servicePort))
113
							}
114
						}
115
					}
116
					if hintPort.Len() > 0 {
117
						warnings = append(warnings, fmt.Sprintf(
118
							"port %d not found for hostname %q (hint: the service port should be specified, not the workload port. Did you mean one of these ports: %v?)",
119
							port, g, sets.SortedList(hintPort)))
120
						foundUnusable = true
121
					} else {
122
						_, isManaged := svc.Attributes.Labels[constants.ManagedGatewayLabel]
123
						var portExistsOnService bool
124
						for _, p := range svc.Ports {
125
							if p.Port == port {
126
								portExistsOnService = true
127
								break
128
							}
129
						}
130
						// If this is a managed gateway, the only possible explanation for no instances for the port
131
						// is a delay in endpoint sync. Therefore, we don't want to warn/change the Programmed condition
132
						// in this case as long as the port exists on the `Service` object.
133
						if !isManaged || !portExistsOnService {
134
							warnings = append(warnings, fmt.Sprintf("port %d not found for hostname %q", port, g))
135
							foundUnusable = true
136
						}
137
					}
138
				}
139
			}
140
		}
141
	}
142
	sort.Strings(warnings)
143
	return sets.SortedList(foundInternal), sets.SortedList(foundInternalIP), sets.SortedList(foundExternal), sets.SortedList(foundPending),
144
		warnings, !foundUnusable
145
}
146

147
func (gc GatewayContext) GetService(hostname, namespace string) *model.Service {
148
	return gc.ps.ServiceIndex.HostnameAndNamespace[host.Name(hostname)][namespace]
149
}
150

151
func instancesEmpty(m map[int][]*model.IstioEndpoint) bool {
152
	for _, instances := range m {
153
		if len(instances) > 0 {
154
			return false
155
		}
156
	}
157
	return true
158
}
159

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.