istio
376 строк · 15.6 Кб
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 ambient
16
17import (
18"net/netip"
19"testing"
20
21corev1 "k8s.io/api/core/v1"
22metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23
24"istio.io/istio/pilot/pkg/features"
25"istio.io/istio/pilot/pkg/model"
26"istio.io/istio/pkg/config/constants"
27"istio.io/istio/pkg/config/schema/gvk"
28"istio.io/istio/pkg/test"
29"istio.io/istio/pkg/test/util/assert"
30"istio.io/istio/pkg/workloadapi"
31)
32
33func TestAmbientIndex_WorkloadEntries(t *testing.T) {
34s := newAmbientTestServer(t, testC, testNW)
35
36s.addWorkloadEntries(t, "127.0.0.1", "name1", "sa1", map[string]string{"app": "a"})
37s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "name1")
38s.assertEvent(t, s.wleXdsName("name1"))
39
40s.addWorkloadEntries(t, "127.0.0.2", "name2", "sa2", map[string]string{"app": "a", "other": "label"})
41s.addWorkloadEntries(t, "127.0.0.3", "name3", "sa3", map[string]string{"app": "other"})
42s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "name1", "name2", "name3")
43s.assertWorkloads(t, s.addrXdsName("127.0.0.1"), workloadapi.WorkloadStatus_HEALTHY, "name1")
44s.assertWorkloads(t, s.addrXdsName("127.0.0.2"), workloadapi.WorkloadStatus_HEALTHY, "name2")
45assert.Equal(t, s.lookup(s.addrXdsName("127.0.0.3")), []model.AddressInfo{{
46Address: &workloadapi.Address{
47Type: &workloadapi.Address_Workload{
48Workload: &workloadapi.Workload{
49Uid: s.wleXdsName("name3"),
50Name: "name3",
51Namespace: testNS,
52Network: testNW,
53Addresses: [][]byte{parseIP("127.0.0.3")},
54ServiceAccount: "sa3",
55Node: "",
56CanonicalName: "other",
57CanonicalRevision: "latest",
58WorkloadType: workloadapi.WorkloadType_POD,
59WorkloadName: "name3",
60ClusterId: testC,
61},
62},
63},
64}})
65s.assertEvent(t, s.wleXdsName("name2"))
66s.assertEvent(t, s.wleXdsName("name3"))
67
68// Non-existent IP should have no response
69s.assertWorkloads(t, s.addrXdsName("10.0.0.1"), workloadapi.WorkloadStatus_HEALTHY)
70s.clearEvents()
71
72s.addService(t, "svc1", map[string]string{}, // labels
73map[string]string{}, // annotations
74[]int32{80},
75map[string]string{"app": "a"}, // selector
76"10.0.0.1",
77)
78// Service shouldn't change workload list
79s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "name1", "name2", "name3")
80s.assertWorkloads(t, s.addrXdsName("127.0.0.1"), workloadapi.WorkloadStatus_HEALTHY, "name1")
81// Now we should be able to look up a VIP as well
82s.assertWorkloads(t, s.addrXdsName("10.0.0.1"), workloadapi.WorkloadStatus_HEALTHY, "name1", "name2")
83// We should get an event for the two WEs and the selecting service impacted
84s.assertEvent(t, s.wleXdsName("name1"), s.wleXdsName("name2"), s.svcXdsName("svc1"))
85
86// Add a new pod to the service, we should see it
87s.addWorkloadEntries(t, "127.0.0.4", "name4", "sa4", map[string]string{"app": "a"})
88s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "name1", "name2", "name3", "name4")
89s.assertWorkloads(t, s.addrXdsName("10.0.0.1"), workloadapi.WorkloadStatus_HEALTHY, "name1", "name2", "name4")
90s.assertEvent(t, s.wleXdsName("name4"))
91
92// Delete it, should remove from the Service as well
93s.deleteWorkloadEntry(t, "name4")
94s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "name1", "name2", "name3")
95s.assertWorkloads(t, s.addrXdsName("10.0.0.1"), workloadapi.WorkloadStatus_HEALTHY, "name1", "name2")
96s.assertWorkloads(t, s.addrXdsName("127.0.0.4"), workloadapi.WorkloadStatus_HEALTHY) // Should not be accessible anymore
97s.assertEvent(t, s.wleXdsName("name4"))
98
99s.clearEvents()
100// Update Service to have a more restrictive label selector
101s.addService(t, "svc1", map[string]string{}, // labels
102map[string]string{}, // annotations
103[]int32{80},
104map[string]string{"app": "a", "other": "label"}, // selector
105"10.0.0.1",
106)
107s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "name1", "name2", "name3")
108s.assertWorkloads(t, s.addrXdsName("10.0.0.1"), workloadapi.WorkloadStatus_HEALTHY, "name2")
109s.assertEvent(t, s.wleXdsName("name1"))
110
111// Update an existing WE into the service
112s.addWorkloadEntries(t, "127.0.0.3", "name3", "sa3", map[string]string{"app": "a", "other": "label"})
113s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "name1", "name2", "name3")
114s.assertWorkloads(t, s.addrXdsName("10.0.0.1"), workloadapi.WorkloadStatus_HEALTHY, "name2", "name3")
115s.assertEvent(t, s.wleXdsName("name3"))
116
117// And remove it again from the service VIP mapping by changing its label to not match the service svc1.ns1 selector
118s.addWorkloadEntries(t, "127.0.0.3", "name3", "sa3", map[string]string{"app": "a"})
119s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "name1", "name2", "name3")
120s.assertWorkloads(t, s.addrXdsName("10.0.0.1"), workloadapi.WorkloadStatus_HEALTHY, "name2")
121s.assertEvent(t, s.wleXdsName("name3"))
122
123// Delete the service entirely
124s.sc.Delete("svc1", "ns1")
125s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "name1", "name2", "name3")
126s.assertWorkloads(t, s.addrXdsName("10.0.0.1"), workloadapi.WorkloadStatus_HEALTHY)
127s.assertEvent(t, s.wleXdsName("name2"), s.svcXdsName("svc1"))
128
129// Add a waypoint proxy pod for namespace
130s.addPods(t, "127.0.0.200", "waypoint-ns-pod", "namespace-wide",
131map[string]string{
132constants.ManagedGatewayLabel: constants.ManagedGatewayMeshControllerLabel,
133constants.GatewayNameLabel: "namespace-wide",
134}, nil, true, corev1.PodRunning)
135s.assertAddresses(t, "", "name1", "name2", "name3", "waypoint-ns-pod")
136s.assertEvent(t, s.podXdsName("waypoint-ns-pod"))
137s.addWaypoint(t, "10.0.0.2", "waypoint-ns", "", true)
138s.ns.CreateOrUpdate(&corev1.Namespace{
139ObjectMeta: metav1.ObjectMeta{
140Name: testNS,
141Annotations: map[string]string{
142constants.AmbientUseWaypoint: "waypoint-ns",
143},
144},
145})
146// All these workloads updated, so push them
147s.assertEvent(t,
148s.wleXdsName("name1"),
149s.wleXdsName("name2"),
150s.wleXdsName("name3"),
151)
152// create the waypoint service
153s.addService(t, "waypoint-ns",
154map[string]string{constants.ManagedGatewayLabel: constants.ManagedGatewayMeshControllerLabel}, // labels
155map[string]string{}, // annotations
156[]int32{80},
157map[string]string{constants.GatewayNameLabel: "namespace-wide"}, // selector
158"10.0.0.2",
159)
160s.assertEvent(t, s.podXdsName("waypoint-ns-pod"),
161s.svcXdsName("waypoint-ns"),
162)
163s.assertAddresses(t, "", "name1", "name2", "name3", "waypoint-ns", "waypoint-ns-pod")
164// We should now see the waypoint service IP
165assert.Equal(t,
166s.lookup(s.addrXdsName("127.0.0.3"))[0].Address.GetWorkload().Waypoint.GetAddress().Address,
167netip.MustParseAddr("10.0.0.2").AsSlice())
168
169// Add another one, expect the same result
170s.addPods(t, "127.0.0.201", "waypoint2-ns-pod", "namespace-wide",
171map[string]string{
172constants.ManagedGatewayLabel: constants.ManagedGatewayMeshControllerLabel,
173constants.GatewayNameLabel: "namespace-wide",
174}, nil, true, corev1.PodRunning)
175s.assertAddresses(t, "", "name1", "name2", "name3", "waypoint-ns", "waypoint-ns-pod", "waypoint2-ns-pod")
176// all these workloads already have a waypoint, only expect the new waypoint pod
177s.assertEvent(t, s.podXdsName("waypoint2-ns-pod"))
178
179// Waypoints do not have waypoints
180assert.Equal(t,
181s.lookup(s.addrXdsName("127.0.0.200"))[0].Address.GetWorkload().GetWaypoint(),
182nil)
183
184s.addService(t, "svc1",
185map[string]string{}, // labels
186map[string]string{}, // annotations
187[]int32{80},
188map[string]string{"app": "a"}, // selector
189"10.0.0.1",
190)
191s.assertWorkloads(t, s.addrXdsName("10.0.0.1"), workloadapi.WorkloadStatus_HEALTHY, "name1", "name2", "name3")
192// Send update for the workloads as well...
193s.assertEvent(t, s.wleXdsName("name1"),
194s.wleXdsName("name2"),
195s.wleXdsName("name3"),
196s.svcXdsName("svc1"))
197
198// Delete a waypoint pod
199s.deletePod(t, "waypoint2-ns-pod")
200s.assertEvent(t, s.podXdsName("waypoint2-ns-pod")) // only expect event on the single waypoint pod
201
202// Adding a new WorkloadEntry should also see the waypoint
203s.addWorkloadEntries(t, "127.0.0.6", "name6", "sa6", map[string]string{"app": "a"})
204s.assertEvent(t, s.wleXdsName("name6"))
205assert.Equal(t,
206s.lookup(s.addrXdsName("127.0.0.6"))[0].Address.GetWorkload().Waypoint.GetAddress().Address,
207netip.MustParseAddr("10.0.0.2").AsSlice())
208
209s.deleteWorkloadEntry(t, "name6")
210s.assertEvent(t, s.wleXdsName("name6"))
211
212s.deleteWaypoint(t, "waypoint-ns")
213s.ns.Update(&corev1.Namespace{
214ObjectMeta: metav1.ObjectMeta{
215Name: testNS,
216Annotations: map[string]string{
217constants.AmbientUseWaypoint: "#none",
218},
219},
220})
221// all affected addresses with the waypoint should be updated
222s.assertEvent(t,
223s.svcXdsName("svc1"),
224s.svcXdsName("waypoint-ns"),
225s.wleXdsName("name1"),
226s.wleXdsName("name2"),
227s.wleXdsName("name3"))
228
229s.deleteService(t, "waypoint-ns")
230s.assertEvent(t, s.podXdsName("waypoint-ns-pod"),
231s.svcXdsName("waypoint-ns"))
232
233s.deleteWorkloadEntry(t, "name3")
234s.assertEvent(t, s.wleXdsName("name3"))
235s.deleteWorkloadEntry(t, "name2")
236s.assertEvent(t, s.wleXdsName("name2"))
237
238s.addPolicy(t, "global", "istio-system", nil, gvk.AuthorizationPolicy, nil)
239s.addPolicy(t, "namespace", "default", nil, gvk.AuthorizationPolicy, nil)
240assert.Equal(t,
241s.lookup(s.addrXdsName("127.0.0.1"))[0].GetWorkload().GetAuthorizationPolicies(),
242nil)
243s.clearEvents()
244
245s.addPolicy(t, "selector", "ns1", map[string]string{"app": "a"}, gvk.AuthorizationPolicy, nil)
246s.assertEvent(t, s.wleXdsName("name1"))
247assert.Equal(t,
248s.lookup(s.addrXdsName("127.0.0.1"))[0].GetWorkload().GetAuthorizationPolicies(),
249[]string{"ns1/selector"})
250
251// WorkloadEntry not in policy
252s.addWorkloadEntries(t, "127.0.0.2", "name2", "sa2", map[string]string{"app": "not-a"})
253s.assertEvent(t, s.wleXdsName("name2"))
254assert.Equal(t,
255s.lookup(s.addrXdsName("127.0.0.2"))[0].GetWorkload().GetAuthorizationPolicies(),
256nil)
257
258// Add it to the policy by updating its selector
259s.addWorkloadEntries(t, "127.0.0.2", "name2", "sa2", map[string]string{"app": "a"})
260s.assertEvent(t, s.wleXdsName("name2"))
261assert.Equal(t,
262s.lookup(s.addrXdsName("127.0.0.2"))[0].GetWorkload().GetAuthorizationPolicies(),
263[]string{"ns1/selector"})
264
265s.addPolicy(t, "global-selector", "istio-system", map[string]string{"app": "a"}, gvk.AuthorizationPolicy, nil)
266s.assertEvent(t, s.wleXdsName("name1"), s.wleXdsName("name2"))
267assert.Equal(t,
268s.lookup(s.addrXdsName("127.0.0.1"))[0].GetWorkload().GetAuthorizationPolicies(),
269[]string{"istio-system/global-selector", "ns1/selector"})
270
271// Update selector to not select
272s.addPolicy(t, "global-selector", "istio-system", map[string]string{"app": "not-a"}, gvk.AuthorizationPolicy, nil)
273s.assertEvent(t, s.wleXdsName("name1"), s.wleXdsName("name2"))
274assert.Equal(t,
275s.lookup(s.addrXdsName("127.0.0.1"))[0].GetWorkload().GetAuthorizationPolicies(),
276[]string{"ns1/selector"})
277
278s.authz.Delete("selector", "ns1")
279s.assertEvent(t, s.wleXdsName("name1"), s.wleXdsName("name2"))
280assert.Equal(t,
281s.lookup(s.addrXdsName("127.0.0.1"))[0].GetWorkload().GetAuthorizationPolicies(),
282nil)
283}
284
285func TestAmbientIndex_EmptyAddrWorkloadEntries(t *testing.T) {
286s := newAmbientTestServer(t, testC, testNW)
287s.addWorkloadEntries(t, "", "emptyaddr1", "sa1", map[string]string{"app": "a"})
288s.assertEvent(t, s.wleXdsName("emptyaddr1"))
289s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "emptyaddr1")
290
291s.addWorkloadEntries(t, "", "emptyaddr2", "sa1", map[string]string{"app": "a"})
292s.assertEvent(t, s.wleXdsName("emptyaddr2"))
293s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "emptyaddr1", "emptyaddr2")
294
295// ensure we stored and can fetch both; neither was blown away
296assert.Equal(t,
297s.lookup(s.wleXdsName("emptyaddr1"))[0].GetWorkload().GetName(),
298"emptyaddr1") // can lookup this workload by name
299assert.Equal(t,
300s.lookup(s.wleXdsName("emptyaddr2"))[0].GetWorkload().GetName(),
301"emptyaddr2") // can lookup this workload by name
302
303assert.Equal(t,
304len(s.lookup(s.addrXdsName(""))),
3050) // cannot lookup these workloads by address
306}
307
308func TestAmbientIndex_UpdateExistingWorkloadEntry(t *testing.T) {
309s := newAmbientTestServer(t, testC, testNW)
310s.addWorkloadEntries(t, "", "emptyaddr1", "sa1", map[string]string{"app": "a"})
311s.assertEvent(t, s.wleXdsName("emptyaddr1"))
312s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "emptyaddr1")
313
314// update service account for existing WE and expect a new xds event
315s.addWorkloadEntries(t, "", "emptyaddr1", "sa2", map[string]string{"app": "a"})
316s.assertEvent(t, s.wleXdsName("emptyaddr1"))
317s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "emptyaddr1")
318}
319
320func TestAmbientIndex_InlinedWorkloadEntries(t *testing.T) {
321s := newAmbientTestServer(t, testC, testNW)
322
323s.addServiceEntry(t, "se.istio.io", []string{"240.240.23.45"}, "se1", testNS, map[string]string{"app": "a"}, []string{"127.0.0.1", "127.0.0.2"})
324s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "se1")
325s.assertEvent(t, s.seIPXdsName("se1", "127.0.0.1"), s.seIPXdsName("se1", "127.0.0.2"), "ns1/se.istio.io")
326
327s.addPolicy(t, "selector", "ns1", map[string]string{"app": "a"}, gvk.AuthorizationPolicy, nil)
328s.assertEvent(t, s.seIPXdsName("se1", "127.0.0.1"), s.seIPXdsName("se1", "127.0.0.2"))
329assert.Equal(t,
330s.lookup(s.seIPXdsName("se1", "127.0.0.1"))[0].GetWorkload().GetAuthorizationPolicies(),
331[]string{"ns1/selector"})
332assert.Equal(t,
333s.lookup(s.seIPXdsName("se1", "127.0.0.2"))[0].GetWorkload().GetAuthorizationPolicies(),
334[]string{"ns1/selector"})
335
336s.deletePolicy("selector", "ns1", gvk.AuthorizationPolicy)
337s.assertEvent(t, s.seIPXdsName("se1", "127.0.0.1"), s.seIPXdsName("se1", "127.0.0.2"))
338assert.Equal(t,
339s.lookup(s.seIPXdsName("se1", "127.0.0.1"))[0].GetWorkload().GetAuthorizationPolicies(),
340nil)
341assert.Equal(t,
342s.lookup(s.seIPXdsName("se1", "127.0.0.2"))[0].GetWorkload().GetAuthorizationPolicies(),
343nil)
344
345s.deleteServiceEntry(t, "se1", testNS)
346s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY) // Asserting no WE residual
347}
348
349func TestAmbientIndex_WorkloadEntries_DisableK8SServiceSelectWorkloadEntries(t *testing.T) {
350test.SetForTest(t, &features.EnableK8SServiceSelectWorkloadEntries, false)
351s := newAmbientTestServer(t, testC, testNW)
352
353s.addWorkloadEntries(t, "127.0.0.1", "name1", "sa1", map[string]string{"app": "a"})
354s.assertEvent(t, s.wleXdsName("name1"))
355s.addWorkloadEntries(t, "127.0.0.2", "name2", "sa2", map[string]string{"app": "a", "other": "label"})
356s.assertEvent(t, s.wleXdsName("name2"))
357s.addWorkloadEntries(t, "127.0.0.3", "name3", "sa3", map[string]string{"app": "other"})
358s.assertEvent(t, s.wleXdsName("name3"))
359s.addPods(t, "127.0.0.201", "pod1", "pod1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
360s.assertEvent(t, s.podXdsName("pod1"))
361
362s.addService(t, "svc1", map[string]string{}, // labels
363map[string]string{}, // annotations
364[]int32{80},
365map[string]string{"app": "a"}, // selector
366"10.0.0.1",
367)
368s.assertEvent(t, s.podXdsName("pod1"), "ns1/svc1.ns1.svc.company.com")
369
370s.clearEvents()
371s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "name1", "name2", "name3", "pod1")
372
373// Setting the PILOT_ENABLE_K8S_SELECT_WORKLOAD_ENTRIES to false shouldn't include workload entries when
374// looking up by the k8s service address
375s.assertWorkloads(t, s.addrXdsName("10.0.0.1"), workloadapi.WorkloadStatus_HEALTHY, "pod1")
376}
377