istio

Форк
0
/
waypoint_test.go 
348 строк · 9.8 Кб
1
//go:build integ
2

3
// Copyright Istio Authors
4
//
5
// Licensed under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
//
9
//     http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing, software
12
// distributed under the License is distributed on an "AS IS" BASIS,
13
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
// See the License for the specific language governing permissions and
15
// limitations under the License.
16

17
package ambient
18

19
import (
20
	"context"
21
	"errors"
22
	"fmt"
23
	"strings"
24
	"testing"
25
	"time"
26

27
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28
	"k8s.io/apimachinery/pkg/types"
29
	k8s "sigs.k8s.io/gateway-api/apis/v1"
30

31
	"istio.io/istio/pilot/pkg/model/kstatus"
32
	"istio.io/istio/pkg/config/constants"
33
	"istio.io/istio/pkg/test/echo/common/scheme"
34
	"istio.io/istio/pkg/test/framework"
35
	"istio.io/istio/pkg/test/framework/components/echo"
36
	"istio.io/istio/pkg/test/framework/components/echo/check"
37
	"istio.io/istio/pkg/test/framework/components/istioctl"
38
	"istio.io/istio/pkg/test/framework/components/namespace"
39
	"istio.io/istio/pkg/test/framework/resource/config/apply"
40
	kubetest "istio.io/istio/pkg/test/kube"
41
	"istio.io/istio/pkg/test/scopes"
42
	"istio.io/istio/pkg/test/util/retry"
43
)
44

45
func TestWaypointStatus(t *testing.T) {
46
	framework.
47
		NewTest(t).
48
		Features("traffic.ambient").
49
		Run(func(t framework.TestContext) {
50
			client := t.Clusters().Kube().Default().GatewayAPI().GatewayV1beta1().GatewayClasses()
51

52
			check := func() error {
53
				gwc, _ := client.Get(context.Background(), constants.WaypointGatewayClassName, metav1.GetOptions{})
54
				if gwc == nil {
55
					return fmt.Errorf("failed to find GatewayClass %v", constants.WaypointGatewayClassName)
56
				}
57
				cond := kstatus.GetCondition(gwc.Status.Conditions, string(k8s.GatewayClassConditionStatusAccepted))
58
				if cond.Status != metav1.ConditionTrue {
59
					return fmt.Errorf("failed to find accepted condition: %+v", cond)
60
				}
61
				if cond.ObservedGeneration != gwc.Generation {
62
					return fmt.Errorf("stale GWC generation: %+v", cond)
63
				}
64
				return nil
65
			}
66
			retry.UntilSuccessOrFail(t, check)
67

68
			// Wipe out the status
69
			gwc, _ := client.Get(context.Background(), constants.WaypointGatewayClassName, metav1.GetOptions{})
70
			gwc.Status.Conditions = nil
71
			client.Update(context.Background(), gwc, metav1.UpdateOptions{})
72
			// It should be added back
73
			retry.UntilSuccessOrFail(t, check)
74
		})
75
}
76

77
func TestWaypoint(t *testing.T) {
78
	framework.
79
		NewTest(t).
80
		Features("traffic.ambient").
81
		Run(func(t framework.TestContext) {
82
			nsConfig := namespace.NewOrFail(t, t, namespace.Config{
83
				Prefix: "waypoint",
84
				Inject: false,
85
				Labels: map[string]string{
86
					constants.DataplaneMode: "ambient",
87
				},
88
			})
89

90
			istioctl.NewOrFail(t, t, istioctl.Config{}).InvokeOrFail(t, []string{
91
				"x",
92
				"waypoint",
93
				"apply",
94
				"--namespace",
95
				nsConfig.Name(),
96
				"--wait",
97
			})
98

99
			saSet := []string{"sa1", "sa2", "sa3"}
100
			for _, sa := range saSet {
101
				istioctl.NewOrFail(t, t, istioctl.Config{}).InvokeOrFail(t, []string{
102
					"x",
103
					"waypoint",
104
					"apply",
105
					"--namespace",
106
					nsConfig.Name(),
107
					"--service-account",
108
					sa,
109
					"--wait",
110
				})
111
			}
112

113
			output, _ := istioctl.NewOrFail(t, t, istioctl.Config{}).InvokeOrFail(t, []string{
114
				"x",
115
				"waypoint",
116
				"list",
117
				"--namespace",
118
				nsConfig.Name(),
119
			})
120
			for _, sa := range saSet {
121
				if !strings.Contains(output, sa) {
122
					t.Fatalf("expect to find %s in output: %s", sa, output)
123
				}
124
			}
125

126
			output, _ = istioctl.NewOrFail(t, t, istioctl.Config{}).InvokeOrFail(t, []string{
127
				"x",
128
				"waypoint",
129
				"list",
130
				"-A",
131
			})
132
			for _, sa := range saSet {
133
				if !strings.Contains(output, sa) {
134
					t.Fatalf("expect to find %s in output: %s", sa, output)
135
				}
136
			}
137

138
			istioctl.NewOrFail(t, t, istioctl.Config{}).InvokeOrFail(t, []string{
139
				"x",
140
				"waypoint",
141
				"-n",
142
				nsConfig.Name(),
143
				"delete",
144
			})
145
			retry.UntilSuccessOrFail(t, func() error {
146
				if err := checkWaypointIsReady(t, nsConfig.Name(), "namespace"); err != nil {
147
					if errors.Is(err, kubetest.ErrNoPodsFetched) {
148
						return nil
149
					}
150
					return fmt.Errorf("failed to check gateway status: %v", err)
151
				}
152
				return fmt.Errorf("failed to clean up gateway in namespace: %s", nsConfig.Name())
153
			}, retry.Timeout(15*time.Second), retry.BackoffDelay(time.Millisecond*100))
154

155
			istioctl.NewOrFail(t, t, istioctl.Config{}).InvokeOrFail(t, []string{
156
				"x",
157
				"waypoint",
158
				"-n",
159
				nsConfig.Name(),
160
				"delete",
161
				"sa1",
162
				"sa2",
163
			})
164
			retry.UntilSuccessOrFail(t, func() error {
165
				for _, sa := range []string{"sa1", "sa2"} {
166
					if err := checkWaypointIsReady(t, nsConfig.Name(), sa); err != nil {
167
						if !errors.Is(err, kubetest.ErrNoPodsFetched) {
168
							return fmt.Errorf("failed to check gateway status: %v", err)
169
						}
170
					} else {
171
						return fmt.Errorf("failed to delete multiple gateways: %s not cleaned up", sa)
172
					}
173
				}
174
				return nil
175
			}, retry.Timeout(15*time.Second), retry.BackoffDelay(time.Millisecond*100))
176

177
			// delete all waypoints in namespace, so sa3 should be deleted
178
			istioctl.NewOrFail(t, t, istioctl.Config{}).InvokeOrFail(t, []string{
179
				"x",
180
				"waypoint",
181
				"-n",
182
				nsConfig.Name(),
183
				"delete",
184
				"--all",
185
			})
186
			retry.UntilSuccessOrFail(t, func() error {
187
				if err := checkWaypointIsReady(t, nsConfig.Name(), "sa3"); err != nil {
188
					if errors.Is(err, kubetest.ErrNoPodsFetched) {
189
						return nil
190
					}
191
					return fmt.Errorf("failed to check gateway status: %v", err)
192
				}
193
				return fmt.Errorf("failed to clean up gateway in namespace: %s", nsConfig.Name())
194
			}, retry.Timeout(15*time.Second), retry.BackoffDelay(time.Millisecond*100))
195
		})
196
}
197

198
func checkWaypointIsReady(t framework.TestContext, ns, name string) error {
199
	fetch := kubetest.NewPodFetch(t.AllClusters()[0], ns, constants.GatewayNameLabel+"="+name)
200
	_, err := kubetest.CheckPodsAreReady(fetch)
201
	return err
202
}
203

204
func TestSimpleHTTPSandwich(t *testing.T) {
205
	framework.
206
		NewTest(t).
207
		Features("traffic.ambient").
208
		Run(func(t framework.TestContext) {
209
			config := `
210
apiVersion: gateway.networking.k8s.io/v1beta1
211
kind: Gateway
212
metadata:
213
  name: {{.Service}}-gateway
214
  namespace: {{.Namespace}}
215
  annotations:
216
    networking.istio.io/address-type: IPAddress
217
    networking.istio.io/service-type: ClusterIP
218
    ambient.istio.io/redirection: enabled
219
spec:
220
  gatewayClassName: istio
221
  listeners:
222
  - name: {{.Service}}-fqdn
223
    hostname: {{.Service}}.{{.Namespace}}.svc.cluster.local
224
    port: {{.Port}}
225
    protocol: HTTP
226
    allowedRoutes:
227
      namespaces:
228
        from: Same
229
  - name: {{.Service}}-svc
230
    hostname: {{.Service}}.{{.Namespace}}.svc
231
    port: {{.Port}}
232
    protocol: HTTP
233
    allowedRoutes:
234
      namespaces:
235
        from: Same
236
  - name: {{.Service}}-namespace
237
    hostname: {{.Service}}.{{.Namespace}}
238
    port: {{.Port}}
239
    protocol: HTTP
240
    allowedRoutes:
241
      namespaces:
242
        from: Same
243
  - name: {{.Service}}-short
244
    hostname: {{.Service}}
245
    port: {{.Port}}
246
    protocol: HTTP
247
    allowedRoutes:
248
      namespaces:
249
        from: Same
250
  # HACK:zTunnel currently expects the HBONE port to always be on the Waypoint's Service 
251
  # This will be fixed in future PRs to both istio and zTunnel. 
252
  - name: fake-hbone-port
253
    port: 15008
254
    protocol: TCP
255
---
256
apiVersion: gateway.networking.k8s.io/v1beta1
257
kind: HTTPRoute
258
metadata:
259
  name: {{.Service}}-httproute
260
spec:
261
  parentRefs:
262
  - name: {{.Service}}-gateway
263
  hostnames:
264
  - {{.Service}}.{{.Namespace}}.svc.cluster.local
265
  - {{.Service}}.{{.Namespace}}.svc
266
  - {{.Service}}.{{.Namespace}}
267
  - {{.Service}}
268
  rules:
269
  - matches:
270
    - path:
271
        type: PathPrefix
272
        value: /
273
    filters:
274
    - type: ResponseHeaderModifier
275
      responseHeaderModifier:
276
        add:
277
        - name: traversed-waypoint
278
          value: {{.Service}}-gateway
279
    backendRefs:
280
    - name: {{.Service}}
281
      port: {{.Port}}
282
      `
283

284
			t.ConfigKube().
285
				New().
286
				Eval(
287
					apps.Namespace.Name(),
288
					map[string]any{
289
						"Service":   Captured,
290
						"Namespace": apps.Namespace.Name(),
291
						"Port":      apps.Captured.PortForName("http").ServicePort,
292
					},
293
					config).
294
				ApplyOrFail(t, apply.CleanupConditionally)
295

296
				// Update use-waypoint for Captured service
297
			for _, c := range t.Clusters().Kube() {
298
				client := c.Kube().CoreV1().Services(apps.Namespace.Name())
299
				setWaypoint := func(waypoint string) error {
300
					annotation := []byte(fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`,
301
						constants.AmbientUseWaypoint, waypoint))
302
					_, err := client.Patch(context.TODO(), Captured, types.MergePatchType, annotation, metav1.PatchOptions{})
303
					return err
304
				}
305

306
				if err := setWaypoint("captured-gateway"); err != nil {
307
					t.Fatal(err)
308
				}
309
				t.Cleanup(func() {
310
					if err := setWaypoint(""); err != nil {
311
						scopes.Framework.Errorf("failed resetting waypoint for %s", Captured)
312
					}
313
				})
314

315
			}
316

317
			// ensure HTTP traffic works with all hostname variants
318
			for _, src := range apps.All {
319
				src := src
320
				if !hboneClient(src) {
321
					// TODO if we hairpinning, don't skip here
322
					continue
323
				}
324
				t.NewSubTestf("from %s", src.ServiceName()).Run(func(t framework.TestContext) {
325
					if src.Config().HasSidecar() {
326
						t.Skip("TODO: sidecars don't properly handle use-waypoint")
327
					}
328
					for _, host := range apps.Captured.Config().HostnameVariants() {
329
						host := host
330
						t.NewSubTestf("to %s", host).Run(func(t framework.TestContext) {
331
							src.CallOrFail(t, echo.CallOptions{
332
								To:      apps.Captured,
333
								Address: host,
334
								Port:    echo.Port{Name: "http"},
335
								Scheme:  scheme.HTTP,
336
								Count:   10,
337
								Check: check.And(
338
									check.OK(),
339
									check.ResponseHeader("traversed-waypoint", "captured-gateway"),
340
								),
341
							})
342
						})
343
					}
344
					apps.Captured.ServiceName()
345
				})
346
			}
347
		})
348
}
349

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

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

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

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