1
// Copyright Istio Authors
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
7
// http://www.apache.org/licenses/LICENSE-2.0
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.
21
corev1 "k8s.io/api/core/v1"
22
net "k8s.io/api/networking/v1"
23
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25
meshconfig "istio.io/api/mesh/v1alpha1"
26
"istio.io/istio/pilot/pkg/model"
27
kubecontroller "istio.io/istio/pilot/pkg/serviceregistry/kube/controller"
28
"istio.io/istio/pkg/config"
29
"istio.io/istio/pkg/config/mesh"
30
"istio.io/istio/pkg/config/schema/gvk"
31
"istio.io/istio/pkg/kube"
32
"istio.io/istio/pkg/kube/kclient/clienttest"
33
"istio.io/istio/pkg/util/sets"
36
func newFakeController() (model.ConfigStoreController, kube.Client) {
37
meshHolder := mesh.NewTestWatcher(&meshconfig.MeshConfig{
38
IngressControllerMode: meshconfig.MeshConfig_DEFAULT,
40
fakeClient := kube.NewFakeClient()
41
return NewController(fakeClient, meshHolder, kubecontroller.Options{}), fakeClient
44
func TestIngressController(t *testing.T) {
45
ingress1 := net.Ingress{
46
ObjectMeta: metav1.ObjectMeta{
47
Namespace: "mock", // goes into backend full name
50
Spec: net.IngressSpec{
51
Rules: []net.IngressRule{
54
IngressRuleValue: net.IngressRuleValue{
55
HTTP: &net.HTTPIngressRuleValue{
56
Paths: []net.HTTPIngressPath{
59
Backend: net.IngressBackend{
60
Service: &net.IngressServiceBackend{
62
Port: net.ServiceBackendPort{
74
IngressRuleValue: net.IngressRuleValue{
75
HTTP: &net.HTTPIngressRuleValue{
76
Paths: []net.HTTPIngressPath{
79
Backend: net.IngressBackend{
80
Service: &net.IngressServiceBackend{
82
Port: net.ServiceBackendPort{
94
IngressRuleValue: net.IngressRuleValue{
95
HTTP: &net.HTTPIngressRuleValue{
96
Paths: []net.HTTPIngressPath{
99
Backend: net.IngressBackend{
100
Service: &net.IngressServiceBackend{
102
Port: net.ServiceBackendPort{
116
ingress2 := net.Ingress{
117
ObjectMeta: metav1.ObjectMeta{
121
Spec: net.IngressSpec{
122
Rules: []net.IngressRule{
125
IngressRuleValue: net.IngressRuleValue{
126
HTTP: &net.HTTPIngressRuleValue{
127
Paths: []net.HTTPIngressPath{
130
Backend: net.IngressBackend{
131
Service: &net.IngressServiceBackend{
133
Port: net.ServiceBackendPort{
147
controller, client := newFakeController()
148
ingress := clienttest.NewWriter[*net.Ingress](t, client)
149
configCh := make(chan config.Config)
151
configHandler := func(_, curr config.Config, event model.Event) {
155
wait := func() config.Config {
157
case x := <-configCh:
159
case <-time.After(time.Second * 10):
160
t.Fatalf("timed out waiting for config")
162
return config.Config{}
165
controller.RegisterEventHandler(gvk.VirtualService, configHandler)
166
stopCh := make(chan struct{})
167
go controller.Run(stopCh)
170
client.RunAndWait(stopCh)
172
ingress.Create(&ingress1)
174
if vs.Name != ingress1.Name+"-"+"virtualservice" || vs.Namespace != ingress1.Namespace {
175
t.Errorf("received unecpected config %v/%v", vs.Namespace, vs.Name)
177
ingress.Update(&ingress2)
179
if vs.Name != ingress1.Name+"-"+"virtualservice" || vs.Namespace != ingress1.Namespace {
180
t.Errorf("received unecpected config %v/%v", vs.Namespace, vs.Name)
184
func TestIngressControllerWithPortName(t *testing.T) {
185
ingressConfig := net.Ingress{
186
ObjectMeta: metav1.ObjectMeta{
190
Spec: net.IngressSpec{
191
Rules: []net.IngressRule{
194
IngressRuleValue: net.IngressRuleValue{
195
HTTP: &net.HTTPIngressRuleValue{
196
Paths: []net.HTTPIngressPath{
199
Backend: net.IngressBackend{
200
Service: &net.IngressServiceBackend{
202
Port: net.ServiceBackendPort{
213
Host: "my2.host.com",
214
IngressRuleValue: net.IngressRuleValue{
215
HTTP: &net.HTTPIngressRuleValue{
216
Paths: []net.HTTPIngressPath{
219
Backend: net.IngressBackend{
220
Service: &net.IngressServiceBackend{
222
Port: net.ServiceBackendPort{
236
serviceConfig := corev1.Service{
237
ObjectMeta: metav1.ObjectMeta{
241
Spec: corev1.ServiceSpec{
242
Ports: []corev1.ServicePort{
251
controller, client := newFakeController()
252
ingress := clienttest.NewWriter[*net.Ingress](t, client)
253
service := clienttest.NewWriter[*corev1.Service](t, client)
254
configCh := make(chan config.Config)
256
configHandler := func(_, curr config.Config, event model.Event) {
260
wait := func() config.Config {
262
case x := <-configCh:
264
case <-time.After(time.Second * 10):
265
t.Fatalf("timed out waiting for config")
267
return config.Config{}
270
controller.RegisterEventHandler(gvk.VirtualService, configHandler)
271
stopCh := make(chan struct{})
272
go controller.Run(stopCh)
275
client.RunAndWait(stopCh)
277
// First create ingress.
278
ingress.Create(&ingressConfig)
280
if vs.Name != ingressConfig.Name+"-"+"virtualservice" || vs.Namespace != ingressConfig.Namespace {
281
t.Errorf("received unecpected config %v/%v", vs.Namespace, vs.Name)
284
// Then we create service.
285
service.Create(&serviceConfig)
287
if vs.Name != ingressConfig.Name+"-"+"virtualservice" || vs.Namespace != ingressConfig.Namespace {
288
t.Errorf("received unecpected config %v/%v", vs.Namespace, vs.Name)
291
// We change service port number.
292
serviceConfig.Spec.Ports[0].Port = 8090
293
service.Update(&serviceConfig)
295
if vs.Name != ingressConfig.Name+"-"+"virtualservice" || vs.Namespace != ingressConfig.Namespace {
296
t.Errorf("received unecpected config %v/%v", vs.Namespace, vs.Name)
300
func TestExtractServicesByPortNameType(t *testing.T) {
301
testCases := []struct {
307
name: "has no port name",
309
ObjectMeta: metav1.ObjectMeta{
310
Namespace: "ingress",
313
Spec: net.IngressSpec{
314
Rules: []net.IngressRule{
317
IngressRuleValue: net.IngressRuleValue{
318
HTTP: &net.HTTPIngressRuleValue{
319
Paths: []net.HTTPIngressPath{
322
Backend: net.IngressBackend{
323
Service: &net.IngressServiceBackend{
325
Port: net.ServiceBackendPort{
341
name: "has no port name",
343
ObjectMeta: metav1.ObjectMeta{
344
Namespace: "ingress",
347
Spec: net.IngressSpec{
348
Rules: []net.IngressRule{
351
IngressRuleValue: net.IngressRuleValue{
352
HTTP: &net.HTTPIngressRuleValue{
353
Paths: []net.HTTPIngressPath{
356
Backend: net.IngressBackend{
357
Service: &net.IngressServiceBackend{
359
Port: net.ServiceBackendPort{
367
Backend: net.IngressBackend{
368
Service: &net.IngressServiceBackend{
370
Port: net.ServiceBackendPort{
381
Host: "my1.host.com",
382
IngressRuleValue: net.IngressRuleValue{
383
HTTP: &net.HTTPIngressRuleValue{
384
Paths: []net.HTTPIngressPath{
387
Backend: net.IngressBackend{
388
Service: &net.IngressServiceBackend{
390
Port: net.ServiceBackendPort{
403
expect: sets.String{}.InsertAll("ingress/bar", "ingress/mock"),
407
for _, testCase := range testCases {
408
t.Run(testCase.name, func(t *testing.T) {
409
if !testCase.expect.Equals(extractServicesByPortNameType(&testCase.input)) {
410
t.Fatal("should be equal.")
416
func TestExtractPorts(t *testing.T) {
417
ports := []corev1.ServicePort{
427
expect := sets.New("80|", "8080|http")
428
if !expect.Equals(extractPorts(ports)) {
429
t.Fatal("should be equal")