istio

Форк
0
128 строк · 4.8 Кб
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
// nolint: gocritic
16
package ambient
17

18
import (
19
	"net/netip"
20
	"strings"
21

22
	v1 "k8s.io/api/core/v1"
23
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24
	"sigs.k8s.io/gateway-api/apis/v1beta1"
25

26
	"istio.io/istio/pkg/config/constants"
27
	"istio.io/istio/pkg/config/schema/gvk"
28
	"istio.io/istio/pkg/kube/krt"
29
	"istio.io/istio/pkg/log"
30
	"istio.io/istio/pkg/ptr"
31
)
32

33
type Waypoint struct {
34
	krt.Named
35

36
	Addresses []netip.Addr
37
}
38

39
func fetchWaypoint(ctx krt.HandlerContext, Waypoints krt.Collection[Waypoint], Namespaces krt.Collection[*v1.Namespace], o metav1.ObjectMeta) *Waypoint {
40
	// namespace to be used when the annotation doesn't include a namespace
41
	fallbackNamespace := o.Namespace
42
	// try fetching the waypoint defined on the object itself
43
	wp, isNone := getUseWaypoint(o, fallbackNamespace)
44
	if isNone {
45
		// we've got a local override here opting out of waypoint
46
		return nil
47
	}
48
	if wp != nil {
49
		// plausible the object has a waypoint defined but that waypoint's underlying gateway is not ready, in this case we'd return nil here even if
50
		// the namespace-defined waypoint is ready and would not be nil... is this OK or should we handle that? Could lead to odd behavior when
51
		// o was reliant on the namespace waypoint and then get's a use-waypoint annotation added before that gateway is ready.
52
		// goes from having a waypoint to having no waypoint and then eventually gets a waypoint back
53
		return krt.FetchOne[Waypoint](ctx, Waypoints, krt.FilterKey(wp.ResourceName()))
54
	}
55

56
	// try fetching the namespace-defined waypoint
57
	namespace := ptr.OrEmpty[*v1.Namespace](krt.FetchOne[*v1.Namespace](ctx, Namespaces, krt.FilterKey(o.Namespace)))
58
	// this probably should never be nil. How would o exist in a namespace we know nothing about? maybe edge case of starting the controller or ns delete?
59
	if namespace != nil {
60
		// toss isNone, we don't need to know /why/ we got nil
61
		wpNamespace, _ := getUseWaypoint(namespace.ObjectMeta, fallbackNamespace)
62
		if wpNamespace != nil {
63
			return krt.FetchOne[Waypoint](ctx, Waypoints, krt.FilterKey(wpNamespace.ResourceName()))
64
		}
65
	}
66

67
	// neither o nor it's namespace has a use-waypoint annotation
68
	return nil
69
}
70

71
// getUseWaypoint takes objectMeta and a defaultNamespace
72
// it looks for the istio.io/use-waypoint annotation and parses it
73
// if there is no namespace provided in the annotation the default namespace will be used
74
// defaultNamespace avoids the need to infer when object meta from a namespace was given
75
func getUseWaypoint(meta metav1.ObjectMeta, defaultNamespace string) (named *krt.Named, isNone bool) {
76
	if annotationValue, ok := meta.Annotations[constants.AmbientUseWaypoint]; ok {
77
		if annotationValue == "#none" || annotationValue == "~" {
78
			return nil, true
79
		}
80
		namespacedName := strings.Split(annotationValue, "/")
81
		switch len(namespacedName) {
82
		case 1:
83
			return &krt.Named{
84
				Name:      namespacedName[0],
85
				Namespace: defaultNamespace,
86
			}, false
87
		case 2:
88
			return &krt.Named{
89
				Name:      namespacedName[1],
90
				Namespace: namespacedName[0],
91
			}, false
92
		default:
93
			// malformed annotation error
94
			log.Errorf("%s/%s, has a malformed %s annotation, value found: %s", meta.GetNamespace(), meta.GetName(), constants.AmbientUseWaypoint, annotationValue)
95
			return nil, false
96
		}
97

98
	}
99
	return nil, false
100
}
101

102
func (w Waypoint) ResourceName() string {
103
	return w.GetNamespace() + "/" + w.GetName()
104
}
105

106
func WaypointsCollection(Gateways krt.Collection[*v1beta1.Gateway]) krt.Collection[Waypoint] {
107
	return krt.NewCollection(Gateways, func(ctx krt.HandlerContext, gateway *v1beta1.Gateway) *Waypoint {
108
		if len(gateway.Status.Addresses) == 0 {
109
			// gateway.Status.Addresses should only be populated once the Waypoint's deployment has at least 1 ready pod, it should never be removed after going ready
110
			// ignore Kubernetes Gateways which aren't waypoints
111
			return nil
112
		}
113
		return &Waypoint{
114
			Named:     krt.NewNamed(gateway),
115
			Addresses: getGatewayAddrs(gateway),
116
		}
117
	}, krt.WithName("Waypoints"))
118
}
119

120
func getGatewayAddrs(gw *v1beta1.Gateway) []netip.Addr {
121
	// Currently, we only look at one address. Probably this should be made more robust
122
	ip, err := netip.ParseAddr(gw.Status.Addresses[0].Value)
123
	if err == nil {
124
		return []netip.Addr{ip}
125
	}
126
	log.Errorf("Unable to parse IP address in status of %v/%v/%v", gvk.KubernetesGateway, gw.Namespace, gw.Name)
127
	return nil
128
}
129

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

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

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

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