istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/model/gateway_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 model
    16  
    17  import (
    18  	"fmt"
    19  	"testing"
    20  
    21  	networking "istio.io/api/networking/v1alpha3"
    22  	"istio.io/istio/pkg/config"
    23  	"istio.io/istio/pkg/util/sets"
    24  )
    25  
    26  // nolint lll
    27  func TestMergeGateways(t *testing.T) {
    28  	gwHTTPFoo := makeConfig("foo1", "not-default", "foo.bar.com", "name1", "http", 7, "ingressgateway", "", networking.ServerTLSSettings_SIMPLE)
    29  	gwHTTPbar := makeConfig("bar1", "not-default", "bar.foo.com", "bname1", "http", 7, "ingressgateway", "", networking.ServerTLSSettings_SIMPLE)
    30  	gwHTTPlocalbar := makeConfig("lcoalbar1", "not-default", "localbar.foo.com", "bname1", "http", 7, "ingressgateway", "127.0.0.1", networking.ServerTLSSettings_SIMPLE)
    31  	gwHTTP2Wildcard := makeConfig("foo5", "not-default", "*", "name5", "http2", 8, "ingressgateway", "", networking.ServerTLSSettings_SIMPLE)
    32  	gwHTTPWildcard := makeConfig("foo3", "not-default", "*", "name3", "http", 8, "ingressgateway", "", networking.ServerTLSSettings_SIMPLE)
    33  	gwTCPWildcard := makeConfig("foo4", "not-default-2", "*", "name4", "tcp", 8, "ingressgateway", "", networking.ServerTLSSettings_SIMPLE)
    34  
    35  	gwHTTPWildcardAlternate := makeConfig("foo2", "not-default", "*", "name2", "http", 7, "ingressgateway2", "", networking.ServerTLSSettings_SIMPLE)
    36  
    37  	gwSimple := makeConfig("foo-simple", "not-default-2", "*.example.com", "https", "HTTPS", 443, "ingressgateway", "", networking.ServerTLSSettings_SIMPLE)
    38  	gwPassthrough := makeConfig("foo-passthrough", "not-default-2", "foo.example.com", "tls-foo", "TLS", 443, "ingressgateway", "", networking.ServerTLSSettings_PASSTHROUGH)
    39  
    40  	// TODO(ramaraochavali): Add more test cases here.
    41  	tests := []struct {
    42  		name               string
    43  		gwConfig           []config.Config
    44  		mergedServersNum   int
    45  		serverNum          int
    46  		serversForRouteNum map[string]int
    47  		gatewaysNum        int
    48  	}{
    49  		{
    50  			"single-server-config",
    51  			[]config.Config{gwHTTPFoo},
    52  			1,
    53  			1,
    54  			map[string]int{"http.7": 1},
    55  			1,
    56  		},
    57  		{
    58  			"two servers on the same port",
    59  			[]config.Config{gwHTTPFoo, gwHTTPbar},
    60  			1,
    61  			2,
    62  			map[string]int{"http.7": 2},
    63  			2,
    64  		},
    65  		{
    66  			"two servers on the same port with different bind",
    67  			[]config.Config{gwHTTPbar, gwHTTPlocalbar},
    68  			2,
    69  			2,
    70  			map[string]int{"http.7": 1, "http.7.127.0.0.1": 1},
    71  			2,
    72  		},
    73  		{
    74  			"same-server-config",
    75  			[]config.Config{gwHTTPFoo, gwHTTPWildcardAlternate},
    76  			1,
    77  			2,
    78  			map[string]int{"http.7": 2},
    79  			2,
    80  		},
    81  		{
    82  			"multi-server-config",
    83  			[]config.Config{gwHTTPFoo, gwHTTPWildcardAlternate, gwHTTPWildcard},
    84  			2,
    85  			3,
    86  			map[string]int{"http.7": 2, "http.8": 1},
    87  			3,
    88  		},
    89  		{
    90  			"http-tcp-wildcard-server-config",
    91  			[]config.Config{gwHTTPFoo, gwTCPWildcard},
    92  			2,
    93  			2,
    94  			map[string]int{"http.7": 1},
    95  			2,
    96  		},
    97  		{
    98  			"tcp-http-server-config",
    99  			[]config.Config{gwTCPWildcard, gwHTTPWildcard},
   100  			1,
   101  			1,
   102  			map[string]int{},
   103  			2,
   104  		},
   105  		{
   106  			"tcp-tcp-server-config",
   107  			[]config.Config{gwHTTPWildcard, gwTCPWildcard}, // order matters
   108  			1,
   109  			1,
   110  			map[string]int{"http.8": 1},
   111  			2,
   112  		},
   113  		{
   114  			"http-http2-server-config",
   115  			[]config.Config{gwHTTPWildcard, gwHTTP2Wildcard},
   116  			1,
   117  			1,
   118  			// http and http2 both present
   119  			map[string]int{"http.8": 1},
   120  			2,
   121  		},
   122  		{
   123  			"simple-passthrough",
   124  			[]config.Config{gwSimple, gwPassthrough},
   125  			2,
   126  			2,
   127  			map[string]int{"https.443.https.foo-simple.not-default-2": 1},
   128  			2,
   129  		},
   130  	}
   131  
   132  	for idx, tt := range tests {
   133  		t.Run(fmt.Sprintf("[%d] %s", idx, tt.name), func(t *testing.T) {
   134  			instances := []gatewayWithInstances{}
   135  			for _, c := range tt.gwConfig {
   136  				instances = append(instances, gatewayWithInstances{c, true, nil})
   137  			}
   138  			mgw := MergeGateways(instances, &Proxy{}, nil)
   139  			if len(mgw.MergedServers) != tt.mergedServersNum {
   140  				t.Errorf("Incorrect number of merged servers. Expected: %v Got: %d", tt.mergedServersNum, len(mgw.MergedServers))
   141  			}
   142  			if len(mgw.ServersByRouteName) != len(tt.serversForRouteNum) {
   143  				t.Errorf("Incorrect number of routes. Expected: %v Got: %d", len(tt.serversForRouteNum), len(mgw.ServersByRouteName))
   144  			}
   145  			for k, v := range mgw.ServersByRouteName {
   146  				if tt.serversForRouteNum[k] != len(v) {
   147  					t.Errorf("for route %v expected %v servers got %v", k, tt.serversForRouteNum[k], len(v))
   148  				}
   149  			}
   150  			ns := 0
   151  			for _, ms := range mgw.MergedServers {
   152  				ns += len(ms.Servers)
   153  			}
   154  			if ns != tt.serverNum {
   155  				t.Errorf("Incorrect number of total servers. Expected: %v Got: %d", tt.serverNum, ns)
   156  			}
   157  			if len(mgw.GatewayNameForServer) != tt.gatewaysNum {
   158  				t.Errorf("Incorrect number of gateways. Expected: %v Got: %d", tt.gatewaysNum, len(mgw.GatewayNameForServer))
   159  			}
   160  		})
   161  	}
   162  }
   163  
   164  func TestGetAutoPassthroughSNIHosts(t *testing.T) {
   165  	gateway := config.Config{
   166  		Meta: config.Meta{
   167  			Name:      "gateway",
   168  			Namespace: "istio-system",
   169  		},
   170  		Spec: &networking.Gateway{
   171  			Selector: map[string]string{"istio": "ingressgateway"},
   172  			Servers: []*networking.Server{
   173  				{
   174  					Hosts: []string{"static.example.com"},
   175  					Port:  &networking.Port{Name: "http", Number: 80, Protocol: "HTTP"},
   176  				},
   177  				{
   178  					Hosts: []string{"www.example.com"},
   179  					Port:  &networking.Port{Name: "https", Number: 443, Protocol: "HTTPS"},
   180  					Tls:   &networking.ServerTLSSettings{Mode: networking.ServerTLSSettings_SIMPLE},
   181  				},
   182  				{
   183  					Hosts: []string{"a.apps.svc.cluster.local", "b.apps.svc.cluster.local"},
   184  					Port:  &networking.Port{Name: "tls", Number: 15443, Protocol: "TLS"},
   185  					Tls:   &networking.ServerTLSSettings{Mode: networking.ServerTLSSettings_AUTO_PASSTHROUGH},
   186  				},
   187  			},
   188  		},
   189  	}
   190  	svc := &Service{
   191  		Attributes: ServiceAttributes{
   192  			Labels: map[string]string{},
   193  		},
   194  	}
   195  	gatewayServiceTargets := []ServiceTarget{
   196  		{
   197  			Service: svc,
   198  			Port: ServiceInstancePort{
   199  				ServicePort: &Port{Port: 80},
   200  				TargetPort:  80,
   201  			},
   202  		},
   203  		{
   204  			Service: svc,
   205  			Port: ServiceInstancePort{
   206  				ServicePort: &Port{Port: 443},
   207  				TargetPort:  443,
   208  			},
   209  		},
   210  		{
   211  			Service: svc,
   212  			Port: ServiceInstancePort{
   213  				ServicePort: &Port{Port: 15443},
   214  				TargetPort:  15443,
   215  			},
   216  		},
   217  	}
   218  	instances := []gatewayWithInstances{{gateway: gateway, instances: gatewayServiceTargets}}
   219  	mgw := MergeGateways(instances, &Proxy{}, nil)
   220  	hosts := mgw.GetAutoPassthrughGatewaySNIHosts()
   221  	expectedHosts := sets.Set[string]{}
   222  	expectedHosts.InsertAll("a.apps.svc.cluster.local", "b.apps.svc.cluster.local")
   223  	if !hosts.Equals(expectedHosts) {
   224  		t.Errorf("expected to get: [a.apps.svc.cluster.local,b.apps.svc.cluster.local], got: %s", hosts.String())
   225  	}
   226  }
   227  
   228  func makeConfig(name, namespace, host, portName, portProtocol string, portNumber uint32, gw string, bind string,
   229  	mode networking.ServerTLSSettings_TLSmode,
   230  ) config.Config {
   231  	c := config.Config{
   232  		Meta: config.Meta{
   233  			Name:      name,
   234  			Namespace: namespace,
   235  		},
   236  		Spec: &networking.Gateway{
   237  			Selector: map[string]string{"istio": gw},
   238  			Servers: []*networking.Server{
   239  				{
   240  					Hosts: []string{host},
   241  					Port:  &networking.Port{Name: portName, Number: portNumber, Protocol: portProtocol},
   242  					Bind:  bind,
   243  					Tls:   &networking.ServerTLSSettings{Mode: mode},
   244  				},
   245  			},
   246  		},
   247  	}
   248  	return c
   249  }
   250  
   251  func TestParseGatewayRDSRouteName(t *testing.T) {
   252  	type args struct {
   253  		name string
   254  	}
   255  	tests := []struct {
   256  		name           string
   257  		args           args
   258  		wantPortNumber int
   259  		wantPortName   string
   260  		wantGateway    string
   261  	}{
   262  		{
   263  			name:           "invalid rds name",
   264  			args:           args{"https.scooby.dooby.doo"},
   265  			wantPortNumber: 0,
   266  			wantPortName:   "",
   267  			wantGateway:    "",
   268  		},
   269  		{
   270  			name:           "gateway http rds name",
   271  			args:           args{"http.80"},
   272  			wantPortNumber: 80,
   273  			wantPortName:   "",
   274  			wantGateway:    "",
   275  		},
   276  		{
   277  			name:           "https rds name",
   278  			args:           args{"https.443.app1.gw1.ns1"},
   279  			wantPortNumber: 443,
   280  			wantPortName:   "app1",
   281  			wantGateway:    "ns1/gw1",
   282  		},
   283  	}
   284  	for _, tt := range tests {
   285  		t.Run(tt.name, func(t *testing.T) {
   286  			gotPortNumber, gotPortName, gotGateway := ParseGatewayRDSRouteName(tt.args.name)
   287  			if gotPortNumber != tt.wantPortNumber {
   288  				t.Errorf("ParseGatewayRDSRouteName() gotPortNumber = %v, want %v", gotPortNumber, tt.wantPortNumber)
   289  			}
   290  			if gotPortName != tt.wantPortName {
   291  				t.Errorf("ParseGatewayRDSRouteName() gotPortName = %v, want %v", gotPortName, tt.wantPortName)
   292  			}
   293  			if gotGateway != tt.wantGateway {
   294  				t.Errorf("ParseGatewayRDSRouteName() gotGateway = %v, want %v", gotGateway, tt.wantGateway)
   295  			}
   296  		})
   297  	}
   298  }