23
corev1 "k8s.io/api/core/v1"
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"
34
type GatewayContext struct {
39
func NewGatewayContext(ps *model.PushContext, cluster cluster.ID) GatewayContext {
40
return GatewayContext{ps, cluster}
53
func (gc GatewayContext) ResolveGatewayInstances(
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{}{}
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]
72
otherNamespaces := []string{}
73
for ns := range gc.ps.ServiceIndex.HostnameAndNamespace[host.Name(g)] {
74
otherNamespaces = append(otherNamespaces, `"`+ns+`"`) // Wrap in quotes for output
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, ", ")))
81
warnings = append(warnings, fmt.Sprintf("hostname %q not found", g))
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...)
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)
104
instancesByPort := gc.ps.ServiceEndpoints(svcKey)
105
if instancesEmpty(instancesByPort) {
106
warnings = append(warnings, fmt.Sprintf("no instances found for hostname %q", g))
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))
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)))
122
_, isManaged := svc.Attributes.Labels[constants.ManagedGatewayLabel]
123
var portExistsOnService bool
124
for _, p := range svc.Ports {
126
portExistsOnService = true
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))
142
sort.Strings(warnings)
143
return sets.SortedList(foundInternal), sets.SortedList(foundInternalIP), sets.SortedList(foundExternal), sets.SortedList(foundPending),
144
warnings, !foundUnusable
147
func (gc GatewayContext) GetService(hostname, namespace string) *model.Service {
148
return gc.ps.ServiceIndex.HostnameAndNamespace[host.Name(hostname)][namespace]
151
func instancesEmpty(m map[int][]*model.IstioEndpoint) bool {
152
for _, instances := range m {
153
if len(instances) > 0 {