istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/serviceregistry/kube/controller/ambient/ambientindex_serviceentry_test.go (about)

     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 ambient
    16  
    17  import (
    18  	"net/netip"
    19  	"testing"
    20  
    21  	corev1 "k8s.io/api/core/v1"
    22  
    23  	"istio.io/istio/pilot/pkg/features"
    24  	"istio.io/istio/pilot/pkg/model"
    25  	"istio.io/istio/pkg/test"
    26  	"istio.io/istio/pkg/test/util/assert"
    27  	"istio.io/istio/pkg/workloadapi"
    28  )
    29  
    30  func TestAmbientIndex_ServiceEntry(t *testing.T) {
    31  	s := newAmbientTestServer(t, testC, testNW)
    32  
    33  	// test code path where service entry creates a workload entry via `ServiceEntry.endpoints`
    34  	// and the inlined WE has a port override
    35  	s.addServiceEntry(t, "se.istio.io", []string{"240.240.23.45"}, "name1", testNS, nil, []string{"127.0.0.1"})
    36  	s.assertEvent(t, s.seIPXdsName("name1", "127.0.0.1"), "ns1/se.istio.io")
    37  	s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "name1")
    38  	assert.Equal(t, s.lookup(s.addrXdsName("127.0.0.1")), []model.AddressInfo{{
    39  		Address: &workloadapi.Address{
    40  			Type: &workloadapi.Address_Workload{
    41  				Workload: &workloadapi.Workload{
    42  					Uid:               s.seIPXdsName("name1", "127.0.0.1"),
    43  					Name:              "name1",
    44  					Namespace:         testNS,
    45  					Addresses:         [][]byte{parseIP("127.0.0.1")},
    46  					Node:              "",
    47  					Network:           testNW,
    48  					CanonicalName:     "name1",
    49  					CanonicalRevision: "latest",
    50  					WorkloadType:      workloadapi.WorkloadType_POD,
    51  					WorkloadName:      "name1",
    52  					Services: map[string]*workloadapi.PortList{
    53  						"ns1/se.istio.io": {
    54  							Ports: []*workloadapi.Port{
    55  								{
    56  									ServicePort: 80,
    57  									TargetPort:  8081, // port is overridden by inlined WE port
    58  								},
    59  							},
    60  						},
    61  					},
    62  					ClusterId: testC,
    63  				},
    64  			},
    65  		},
    66  	}})
    67  
    68  	s.deleteServiceEntry(t, "name1", testNS)
    69  	s.assertEvent(t, s.seIPXdsName("name1", "127.0.0.1"), "ns1/se.istio.io")
    70  	assert.Equal(t, s.lookup(s.addrXdsName("127.0.0.1")), nil)
    71  	s.clearEvents()
    72  
    73  	// workload entry that has an address of future pod will be dropped from result once pod is added
    74  	s.addWorkloadEntries(t, "140.140.0.10", "name0", "sa1", map[string]string{"app": "a"})
    75  	s.assertEvent(t, s.wleXdsName("name0"))
    76  	// workload entry is included in the result until pod1 with the same address below is added
    77  	s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "name0")
    78  	// lookup by address should return the workload entry's address info
    79  	assert.Equal(t, s.lookup(s.addrXdsName("140.140.0.10")), []model.AddressInfo{{
    80  		Address: &workloadapi.Address{
    81  			Type: &workloadapi.Address_Workload{
    82  				Workload: &workloadapi.Workload{
    83  					Uid:               s.wleXdsName("name0"),
    84  					Name:              "name0",
    85  					Namespace:         testNS,
    86  					Addresses:         [][]byte{parseIP("140.140.0.10")},
    87  					Network:           testNW,
    88  					CanonicalName:     "a",
    89  					CanonicalRevision: "latest",
    90  					ServiceAccount:    "sa1",
    91  					WorkloadType:      workloadapi.WorkloadType_POD,
    92  					WorkloadName:      "name0",
    93  					ClusterId:         testC,
    94  				},
    95  			},
    96  		},
    97  	}})
    98  
    99  	// test code path where service entry selects workloads via `ServiceEntry.workloadSelector`
   100  	s.addPods(t, "140.140.0.10", "pod1", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
   101  	s.assertEvent(t, s.podXdsName("pod1"))
   102  
   103  	// lookup by address should return the pod's address info (ignore the workload entry with similar address)
   104  	assert.Equal(t, s.lookup(s.addrXdsName("140.140.0.10")), []model.AddressInfo{{
   105  		Address: &workloadapi.Address{
   106  			Type: &workloadapi.Address_Workload{
   107  				Workload: &workloadapi.Workload{
   108  					Uid:               s.podXdsName("pod1"),
   109  					Name:              "pod1",
   110  					Namespace:         testNS,
   111  					Addresses:         [][]byte{parseIP("140.140.0.10")},
   112  					Network:           testNW,
   113  					ClusterId:         testC,
   114  					Node:              "node1",
   115  					CanonicalName:     "a",
   116  					CanonicalRevision: "latest",
   117  					ServiceAccount:    "sa1",
   118  					WorkloadType:      workloadapi.WorkloadType_POD,
   119  					WorkloadName:      "pod1",
   120  				},
   121  			},
   122  		},
   123  	}})
   124  
   125  	s.addPods(t, "140.140.0.11", "pod2", "sa1", map[string]string{"app": "other"}, nil, true, corev1.PodRunning)
   126  	s.assertEvent(t, s.podXdsName("pod2"))
   127  	s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "pod1", "pod2")
   128  	s.addWorkloadEntries(t, "240.240.34.56", "name1", "sa1", map[string]string{"app": "a"})
   129  	s.assertEvent(t, s.wleXdsName("name1"))
   130  	s.addWorkloadEntries(t, "240.240.34.57", "name2", "sa1", map[string]string{"app": "other"})
   131  	s.assertEvent(t, s.wleXdsName("name2"))
   132  	s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "pod1", "pod2", "name1", "name2")
   133  
   134  	s.addWorkloadEntries(t, "140.140.0.11", "name3", "sa1", map[string]string{"app": "other"})
   135  	s.assertEvent(t, s.wleXdsName("name3"))
   136  	s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "pod1", "pod2", "name1", "name2")
   137  
   138  	// a service entry should not be able to select across namespaces
   139  	s.addServiceEntry(t, "mismatched.istio.io", []string{"240.240.23.45"}, "name1", "mismatched-ns", map[string]string{"app": "a"}, nil)
   140  	s.assertEvent(t, "mismatched-ns/mismatched.istio.io")
   141  	assert.Equal(t, s.lookup(s.addrXdsName("140.140.0.10")), []model.AddressInfo{{
   142  		Address: &workloadapi.Address{
   143  			Type: &workloadapi.Address_Workload{
   144  				Workload: &workloadapi.Workload{
   145  					Uid:               s.podXdsName("pod1"),
   146  					Name:              "pod1",
   147  					Namespace:         testNS,
   148  					Addresses:         [][]byte{parseIP("140.140.0.10")},
   149  					Node:              "node1",
   150  					Network:           testNW,
   151  					CanonicalName:     "a",
   152  					CanonicalRevision: "latest",
   153  					ServiceAccount:    "sa1",
   154  					WorkloadType:      workloadapi.WorkloadType_POD,
   155  					WorkloadName:      "pod1",
   156  					Services:          nil, // should not be selected by the mismatched service entry
   157  					ClusterId:         testC,
   158  				},
   159  			},
   160  		},
   161  	}})
   162  	assert.Equal(t, s.lookup(s.addrXdsName("240.240.34.56")), []model.AddressInfo{{
   163  		Address: &workloadapi.Address{
   164  			Type: &workloadapi.Address_Workload{
   165  				Workload: &workloadapi.Workload{
   166  					Uid:               s.wleXdsName("name1"),
   167  					Name:              "name1",
   168  					Namespace:         testNS,
   169  					Addresses:         [][]byte{parseIP("240.240.34.56")},
   170  					Node:              "",
   171  					Network:           testNW,
   172  					CanonicalName:     "a",
   173  					CanonicalRevision: "latest",
   174  					ServiceAccount:    "sa1",
   175  					WorkloadType:      workloadapi.WorkloadType_POD,
   176  					WorkloadName:      "name1",
   177  					Services:          nil, // should not be selected by the mismatched service entry
   178  					ClusterId:         testC,
   179  				},
   180  			},
   181  		},
   182  	}})
   183  
   184  	s.addServiceEntry(t, "se.istio.io", []string{"240.240.23.45"}, "name1", testNS, map[string]string{"app": "a"}, nil)
   185  	s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "pod1", "pod2", "name1", "name2")
   186  	// we should see an update for the workloads selected by the service entry
   187  	// do not expect event for pod2 since it is not selected by the service entry
   188  	s.assertEvent(t, s.podXdsName("pod1"), s.wleXdsName("name0"), s.wleXdsName("name1"), "ns1/se.istio.io")
   189  
   190  	assert.Equal(t, s.lookup(s.addrXdsName("140.140.0.10")), []model.AddressInfo{{
   191  		Address: &workloadapi.Address{
   192  			Type: &workloadapi.Address_Workload{
   193  				Workload: &workloadapi.Workload{
   194  					Uid:               s.podXdsName("pod1"),
   195  					Name:              "pod1",
   196  					Namespace:         testNS,
   197  					Addresses:         [][]byte{parseIP("140.140.0.10")},
   198  					Node:              "node1",
   199  					Network:           testNW,
   200  					CanonicalName:     "a",
   201  					CanonicalRevision: "latest",
   202  					ServiceAccount:    "sa1",
   203  					WorkloadType:      workloadapi.WorkloadType_POD,
   204  					WorkloadName:      "pod1",
   205  					Services: map[string]*workloadapi.PortList{
   206  						"ns1/se.istio.io": {
   207  							Ports: []*workloadapi.Port{
   208  								{
   209  									ServicePort: 80,
   210  									TargetPort:  8080,
   211  								},
   212  							},
   213  						},
   214  					},
   215  					ClusterId: testC,
   216  				},
   217  			},
   218  		},
   219  	}})
   220  
   221  	assert.Equal(t, s.lookup(s.addrXdsName("140.140.0.11")), []model.AddressInfo{{
   222  		Address: &workloadapi.Address{
   223  			Type: &workloadapi.Address_Workload{
   224  				Workload: &workloadapi.Workload{
   225  					Uid:               s.podXdsName("pod2"),
   226  					Name:              "pod2",
   227  					Namespace:         testNS,
   228  					Addresses:         [][]byte{parseIP("140.140.0.11")},
   229  					Node:              "node1",
   230  					Network:           testNW,
   231  					ClusterId:         testC,
   232  					CanonicalName:     "other",
   233  					CanonicalRevision: "latest",
   234  					ServiceAccount:    "sa1",
   235  					WorkloadType:      workloadapi.WorkloadType_POD,
   236  					WorkloadName:      "pod2",
   237  					Services:          nil, // labels don't match workloadSelector, this should be nil
   238  				},
   239  			},
   240  		},
   241  	}})
   242  
   243  	assert.Equal(t, s.lookup(s.addrXdsName("240.240.34.56")), []model.AddressInfo{{
   244  		Address: &workloadapi.Address{
   245  			Type: &workloadapi.Address_Workload{
   246  				Workload: &workloadapi.Workload{
   247  					Uid:               s.wleXdsName("name1"),
   248  					Name:              "name1",
   249  					Namespace:         testNS,
   250  					Addresses:         [][]byte{parseIP("240.240.34.56")},
   251  					Node:              "",
   252  					Network:           testNW,
   253  					CanonicalName:     "a",
   254  					CanonicalRevision: "latest",
   255  					ServiceAccount:    "sa1",
   256  					WorkloadType:      workloadapi.WorkloadType_POD,
   257  					WorkloadName:      "name1",
   258  					Services: map[string]*workloadapi.PortList{
   259  						"ns1/se.istio.io": {
   260  							Ports: []*workloadapi.Port{
   261  								{
   262  									ServicePort: 80,
   263  									TargetPort:  8080,
   264  								},
   265  							},
   266  						},
   267  					},
   268  					ClusterId: testC,
   269  				},
   270  			},
   271  		},
   272  	}})
   273  
   274  	s.deleteServiceEntry(t, "name1", testNS)
   275  	s.assertWorkloads(t, "", workloadapi.WorkloadStatus_HEALTHY, "pod1", "pod2", "name1", "name2")
   276  	s.assertUniqueWorkloads(t)
   277  	// we should see an update for the workloads selected by the service entry
   278  	s.assertEvent(t, s.podXdsName("pod1"), s.wleXdsName("name0"), s.wleXdsName("name1"), "ns1/se.istio.io")
   279  	assert.Equal(t, s.lookup(s.addrXdsName("140.140.0.10")), []model.AddressInfo{{
   280  		Address: &workloadapi.Address{
   281  			Type: &workloadapi.Address_Workload{
   282  				Workload: &workloadapi.Workload{
   283  					Uid:               s.podXdsName("pod1"),
   284  					Name:              "pod1",
   285  					Namespace:         testNS,
   286  					Addresses:         [][]byte{parseIP("140.140.0.10")},
   287  					Node:              "node1",
   288  					Network:           testNW,
   289  					ClusterId:         testC,
   290  					CanonicalName:     "a",
   291  					CanonicalRevision: "latest",
   292  					ServiceAccount:    "sa1",
   293  					WorkloadType:      workloadapi.WorkloadType_POD,
   294  					WorkloadName:      "pod1",
   295  					Services:          nil, // vips for pod1 should be gone now
   296  				},
   297  			},
   298  		},
   299  	}})
   300  
   301  	assert.Equal(t, s.lookup(s.addrXdsName("240.240.34.56")), []model.AddressInfo{{
   302  		Address: &workloadapi.Address{
   303  			Type: &workloadapi.Address_Workload{
   304  				Workload: &workloadapi.Workload{
   305  					Uid:               s.wleXdsName("name1"),
   306  					Name:              "name1",
   307  					Namespace:         testNS,
   308  					Addresses:         [][]byte{parseIP("240.240.34.56")},
   309  					Node:              "",
   310  					Network:           testNW,
   311  					CanonicalName:     "a",
   312  					CanonicalRevision: "latest",
   313  					ServiceAccount:    "sa1",
   314  					WorkloadType:      workloadapi.WorkloadType_POD,
   315  					WorkloadName:      "name1",
   316  					Services:          nil, // vips for workload entry 1 should be gone now
   317  					ClusterId:         testC,
   318  				},
   319  			},
   320  		},
   321  	}})
   322  }
   323  
   324  func TestAmbientIndex_ServiceEntry_DisableK8SServiceSelectWorkloadEntries(t *testing.T) {
   325  	test.SetForTest(t, &features.EnableK8SServiceSelectWorkloadEntries, false)
   326  	s := newAmbientTestServer(t, testC, testNW)
   327  
   328  	s.addPods(t, "140.140.0.10", "pod1", "sa1", map[string]string{"app": "a"}, nil, true, corev1.PodRunning)
   329  	s.assertEvent(t, s.podXdsName("pod1"))
   330  	s.addPods(t, "140.140.0.11", "pod2", "sa1", map[string]string{"app": "other"}, nil, true, corev1.PodRunning)
   331  	s.assertEvent(t, s.podXdsName("pod2"))
   332  	s.addWorkloadEntries(t, "240.240.34.56", "name1", "sa1", map[string]string{"app": "a"})
   333  	s.assertEvent(t, s.wleXdsName("name1"))
   334  	s.addWorkloadEntries(t, "240.240.34.57", "name2", "sa1", map[string]string{"app": "other"})
   335  	s.assertEvent(t, s.wleXdsName("name2"))
   336  	s.addServiceEntry(t, "se.istio.io", []string{"240.240.23.45"}, "name1", testNS, map[string]string{"app": "a"}, nil)
   337  	s.assertEvent(t, s.podXdsName("pod1"), s.wleXdsName("name1"), "ns1/se.istio.io")
   338  	s.clearEvents()
   339  
   340  	// Setting the PILOT_ENABLE_K8S_SELECT_WORKLOAD_ENTRIES to false shouldn't affect the workloads selected by the service
   341  	// entry
   342  	s.assertWorkloads(t, s.addrXdsName("240.240.23.45"), workloadapi.WorkloadStatus_HEALTHY, "pod1", "name1")
   343  }
   344  
   345  func parseIP(ip string) []byte {
   346  	addr, err := netip.ParseAddr(ip)
   347  	if err != nil {
   348  		return nil
   349  	}
   350  	return addr.AsSlice()
   351  }