github.com/kiali/kiali@v1.84.0/business/checkers/gateways/multi_match_checker_test.go (about)

     1  package gateways
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/assert"
     7  	networking_v1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
     8  
     9  	"github.com/kiali/kiali/config"
    10  	"github.com/kiali/kiali/models"
    11  	"github.com/kiali/kiali/tests/data"
    12  )
    13  
    14  func TestCorrectGateways(t *testing.T) {
    15  	conf := config.NewConfig()
    16  	config.Set(conf)
    17  
    18  	assert := assert.New(t)
    19  
    20  	gwObject := data.AddServerToGateway(data.CreateServer([]string{"valid"}, 80, "http", "http"),
    21  		data.CreateEmptyGateway("validgateway", "test", map[string]string{
    22  			"app": "real",
    23  		}))
    24  
    25  	gws := []*networking_v1beta1.Gateway{gwObject}
    26  
    27  	vals := MultiMatchChecker{
    28  		Gateways: gws,
    29  	}.Check()
    30  
    31  	assert.Empty(vals)
    32  	_, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "validgateway"}]
    33  	assert.False(ok)
    34  }
    35  
    36  func TestCaseMatching(t *testing.T) {
    37  	conf := config.NewConfig()
    38  	config.Set(conf)
    39  
    40  	assert := assert.New(t)
    41  
    42  	gwObject := data.AddServerToGateway(data.CreateServer(
    43  		[]string{
    44  			"NOTFINE.example.com",
    45  			"notfine.example.com",
    46  		}, 80, "http", "http"),
    47  
    48  		data.CreateEmptyGateway("foxxed", "test", map[string]string{
    49  			"app": "canidae",
    50  		}))
    51  
    52  	gws := []*networking_v1beta1.Gateway{gwObject}
    53  
    54  	vals := MultiMatchChecker{
    55  		Gateways: gws,
    56  	}.Check()
    57  
    58  	assert.NotEmpty(vals)
    59  	assert.Equal(1, len(vals))
    60  	validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "foxxed"}]
    61  	assert.True(ok)
    62  	assert.True(validation.Valid)
    63  }
    64  
    65  func TestDashSubdomainMatching(t *testing.T) {
    66  	conf := config.NewConfig()
    67  	config.Set(conf)
    68  
    69  	assert := assert.New(t)
    70  
    71  	gwObject := data.AddServerToGateway(data.CreateServer(
    72  		[]string{
    73  			"api.dev.example.com",
    74  			"api-dev.example.com",
    75  		}, 80, "http", "http"),
    76  
    77  		data.CreateEmptyGateway("foxxed", "test", map[string]string{
    78  			"app": "canidae",
    79  		}))
    80  
    81  	gws := []*networking_v1beta1.Gateway{gwObject}
    82  
    83  	vals := MultiMatchChecker{
    84  		Gateways: gws,
    85  	}.Check()
    86  
    87  	assert.Empty(vals)
    88  }
    89  
    90  // Two gateways can share port+host unless they use different ingress
    91  func TestSameHostPortConfigInDifferentIngress(t *testing.T) {
    92  	conf := config.NewConfig()
    93  	config.Set(conf)
    94  
    95  	assert := assert.New(t)
    96  
    97  	gwObject := data.AddServerToGateway(data.CreateServer([]string{"reviews"}, 80, "http", "http"),
    98  		data.CreateEmptyGateway("validgateway", "test", map[string]string{
    99  			"app": "istio-ingress-pub",
   100  		}))
   101  
   102  	// Another namespace
   103  	gwObject2 := data.AddServerToGateway(data.CreateServer([]string{"reviews"}, 80, "http", "http"),
   104  		data.CreateEmptyGateway("stillvalid", "test", map[string]string{
   105  			"app": "istio-ingress-prv",
   106  		}))
   107  
   108  	gws := []*networking_v1beta1.Gateway{gwObject, gwObject2}
   109  
   110  	vals := MultiMatchChecker{
   111  		Gateways: gws,
   112  	}.Check()
   113  
   114  	assert.Equal(0, len(vals))
   115  }
   116  
   117  func TestSameHostPortConfigInDifferentNamespace(t *testing.T) {
   118  	conf := config.NewConfig()
   119  	config.Set(conf)
   120  
   121  	assert := assert.New(t)
   122  
   123  	gwObject := data.AddServerToGateway(data.CreateServer([]string{"valid"}, 80, "http", "http"),
   124  		data.CreateEmptyGateway("validgateway", "test", map[string]string{
   125  			"app": "real",
   126  		}))
   127  
   128  	// Another namespace
   129  	gwObject2 := data.AddServerToGateway(data.CreateServer([]string{"valid"}, 80, "http", "http"),
   130  		data.CreateEmptyGateway("stillvalid", "bookinfo", map[string]string{
   131  			"app": "real",
   132  		}))
   133  
   134  	gws := []*networking_v1beta1.Gateway{gwObject, gwObject2}
   135  
   136  	vals := MultiMatchChecker{
   137  		Gateways: gws,
   138  	}.Check()
   139  
   140  	assert.NotEmpty(vals)
   141  	assert.Equal(2, len(vals))
   142  	validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "bookinfo", Name: "stillvalid"}]
   143  	assert.True(ok)
   144  	assert.True(validation.Valid)
   145  
   146  	secValidation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "validgateway"}]
   147  	assert.True(ok)
   148  	assert.True(secValidation.Valid)
   149  
   150  	// Check references
   151  	assert.Equal(1, len(validation.References))
   152  	assert.Equal(1, len(secValidation.References))
   153  }
   154  
   155  func TestSameHostDifferentPortConfig(t *testing.T) {
   156  	conf := config.NewConfig()
   157  	config.Set(conf)
   158  
   159  	assert := assert.New(t)
   160  
   161  	gwObject := data.AddServerToGateway(data.CreateServer([]string{"valid"}, 80, "http", "http"),
   162  		data.CreateEmptyGateway("validgateway", "test", map[string]string{
   163  			"istio": "istio-ingress",
   164  		}))
   165  
   166  	gwObject2 := data.AddServerToGateway(data.CreateServer([]string{"valid"}, 443, "https", "https"),
   167  		data.CreateEmptyGateway("validgateway", "test", map[string]string{
   168  			"istio": "istio-ingress",
   169  		}))
   170  
   171  	gws := []*networking_v1beta1.Gateway{gwObject, gwObject2}
   172  
   173  	vals := MultiMatchChecker{
   174  		Gateways: gws,
   175  	}.Check()
   176  
   177  	assert.Equal(0, len(vals))
   178  }
   179  
   180  func TestWildCardMatchingHost(t *testing.T) {
   181  	conf := config.NewConfig()
   182  	config.Set(conf)
   183  
   184  	assert := assert.New(t)
   185  
   186  	gwObject := data.AddServerToGateway(data.CreateServer([]string{"valid"}, 80, "http", "http"),
   187  		data.CreateEmptyGateway("validgateway", "test", map[string]string{
   188  			"istio": "istio-ingress",
   189  		}))
   190  
   191  	// Another namespace
   192  	gwObject2 := data.AddServerToGateway(data.CreateServer([]string{"*"}, 80, "http", "http"),
   193  		data.CreateEmptyGateway("stillvalid", "test", map[string]string{
   194  			"istio": "istio-ingress",
   195  		}))
   196  
   197  	// Another namespace
   198  	gwObject3 := data.AddServerToGateway(data.CreateServer([]string{"*.justhost.com"}, 80, "http", "http"),
   199  		data.CreateEmptyGateway("keepsvalid", "test", map[string]string{
   200  			"istio": "istio-ingress",
   201  		}))
   202  
   203  	gws := []*networking_v1beta1.Gateway{gwObject, gwObject2, gwObject3}
   204  
   205  	vals := MultiMatchChecker{
   206  		Gateways: gws,
   207  	}.Check()
   208  
   209  	assert.NotEmpty(vals)
   210  	assert.Equal(3, len(vals))
   211  	validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "stillvalid"}]
   212  	assert.True(ok)
   213  	assert.True(validation.Valid)
   214  
   215  	// valid should have "*" as ref
   216  	// "*" should have valid and *.just as ref
   217  	// *.just should have "*" as ref
   218  	for _, v := range vals {
   219  		if v.Name == "stillvalid" {
   220  			assert.Equal(2, len(v.References))
   221  		} else {
   222  			assert.Equal(1, len(v.References))
   223  		}
   224  	}
   225  }
   226  
   227  func TestSkipWildCardMatchingHost(t *testing.T) {
   228  	conf := config.NewConfig()
   229  	conf.KialiFeatureFlags.Validations.SkipWildcardGatewayHosts = true
   230  	config.Set(conf)
   231  
   232  	assert := assert.New(t)
   233  
   234  	gwObject := data.AddServerToGateway(data.CreateServer([]string{"valid"}, 80, "http", "http"),
   235  		data.CreateEmptyGateway("validgateway", "test", map[string]string{
   236  			"istio": "istio-ingress",
   237  		}))
   238  
   239  	// Another namespace
   240  	gwObject2 := data.AddServerToGateway(data.CreateServer([]string{"*"}, 80, "http", "http"),
   241  		data.CreateEmptyGateway("stillvalid", "test", map[string]string{
   242  			"istio": "istio-ingress",
   243  		}))
   244  
   245  	// Another namespace
   246  	gwObject3 := data.AddServerToGateway(data.CreateServer([]string{"*.justhost.com"}, 80, "http", "http"),
   247  		data.CreateEmptyGateway("keepsvalid", "test", map[string]string{
   248  			"istio": "istio-ingress",
   249  		}))
   250  
   251  	gws := []*networking_v1beta1.Gateway{gwObject, gwObject2, gwObject3}
   252  
   253  	vals := MultiMatchChecker{
   254  		Gateways: gws,
   255  	}.Check()
   256  
   257  	assert.Equal(0, len(vals))
   258  }
   259  
   260  func TestSameWildcardHostPortConfigInDifferentNamespace(t *testing.T) {
   261  	conf := config.NewConfig()
   262  	config.Set(conf)
   263  
   264  	assert := assert.New(t)
   265  
   266  	gwObject := data.AddServerToGateway(data.CreateServer([]string{"*"}, 80, "http", "http"),
   267  		data.CreateEmptyGateway("bookinfo-gateway-auto-host", "bookinfo", map[string]string{}))
   268  
   269  	// Another namespace
   270  	gwObject2 := data.AddServerToGateway(data.CreateServer([]string{"*"}, 80, "http", "http"),
   271  		data.CreateEmptyGateway("bookinfo-gateway-auto-host-copy", "bookinfo2", map[string]string{}))
   272  
   273  	gws := []*networking_v1beta1.Gateway{gwObject, gwObject2}
   274  
   275  	vals := MultiMatchChecker{
   276  		Gateways: gws,
   277  	}.Check()
   278  
   279  	assert.NotEmpty(vals)
   280  	assert.Equal(2, len(vals))
   281  	validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "bookinfo2", Name: "bookinfo-gateway-auto-host-copy"}]
   282  	assert.True(ok)
   283  	assert.True(validation.Valid)
   284  
   285  	secValidation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "bookinfo", Name: "bookinfo-gateway-auto-host"}]
   286  	assert.True(ok)
   287  	assert.True(secValidation.Valid)
   288  
   289  	// Check references
   290  	assert.Equal(1, len(validation.References))
   291  	assert.Equal(1, len(secValidation.References))
   292  }
   293  
   294  func TestAnotherSubdomainWildcardCombination(t *testing.T) {
   295  	conf := config.NewConfig()
   296  	config.Set(conf)
   297  
   298  	assert := assert.New(t)
   299  
   300  	gwObject := data.AddServerToGateway(data.CreateServer(
   301  		[]string{
   302  			"*.echidna.com",
   303  			"tachyglossa.echidna.com",
   304  		}, 80, "http", "http"),
   305  
   306  		data.CreateEmptyGateway("shouldnotbevalid", "test", map[string]string{
   307  			"app": "monotreme",
   308  		}))
   309  
   310  	gws := []*networking_v1beta1.Gateway{gwObject}
   311  
   312  	vals := MultiMatchChecker{
   313  		Gateways: gws,
   314  	}.Check()
   315  
   316  	assert.NotEmpty(vals)
   317  	assert.Equal(1, len(vals))
   318  	validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "shouldnotbevalid"}]
   319  	assert.True(ok)
   320  	assert.True(validation.Valid)
   321  }
   322  
   323  func TestNoMatchOnSubdomainHost(t *testing.T) {
   324  	conf := config.NewConfig()
   325  	config.Set(conf)
   326  
   327  	assert := assert.New(t)
   328  
   329  	gwObject := data.AddServerToGateway(data.CreateServer(
   330  		[]string{
   331  			"example.com",
   332  			"thisisfine.example.com",
   333  		}, 80, "http", "http"),
   334  
   335  		data.CreateEmptyGateway("shouldbevalid", "test", map[string]string{
   336  			"app": "someother",
   337  		}))
   338  
   339  	gws := []*networking_v1beta1.Gateway{gwObject}
   340  
   341  	vals := MultiMatchChecker{
   342  		Gateways: gws,
   343  	}.Check()
   344  
   345  	assert.Empty(vals)
   346  }
   347  
   348  func TestTwoWildCardsMatching(t *testing.T) {
   349  	conf := config.NewConfig()
   350  	config.Set(conf)
   351  
   352  	assert := assert.New(t)
   353  
   354  	gwObject := data.AddServerToGateway(data.CreateServer([]string{"*"}, 80, "http", "http"),
   355  		data.CreateEmptyGateway("validgateway", "test", map[string]string{
   356  			"istio": "istio-ingress",
   357  		}))
   358  
   359  	// Another namespace
   360  	gwObject2 := data.AddServerToGateway(data.CreateServer([]string{"*"}, 80, "http", "http"),
   361  		data.CreateEmptyGateway("stillvalid", "test", map[string]string{
   362  			"istio": "istio-ingress",
   363  		}))
   364  
   365  	gws := []*networking_v1beta1.Gateway{gwObject, gwObject2}
   366  
   367  	vals := MultiMatchChecker{
   368  		Gateways: gws,
   369  	}.Check()
   370  
   371  	assert.NotEmpty(vals)
   372  	assert.Equal(2, len(vals))
   373  	validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "stillvalid"}]
   374  	assert.True(ok)
   375  	assert.True(validation.Valid)
   376  	assert.Equal("spec/servers[0]/hosts[0]", validation.Checks[0].Path)
   377  }
   378  
   379  func TestDuplicateGatewaysErrorCount(t *testing.T) {
   380  	conf := config.NewConfig()
   381  	config.Set(conf)
   382  
   383  	assert := assert.New(t)
   384  
   385  	gwObject := data.AddServerToGateway(data.CreateServer([]string{"valid", "second.valid"}, 80, "http", "http"),
   386  		data.CreateEmptyGateway("validgateway", "test", map[string]string{
   387  			"app": "real",
   388  		}))
   389  
   390  	gwObjectIdentical := data.AddServerToGateway(data.CreateServer([]string{"valid", "second.valid"}, 80, "http", "http"),
   391  		data.CreateEmptyGateway("duplicatevalidgateway", "test", map[string]string{
   392  			"app": "real",
   393  		}))
   394  
   395  	gws := []*networking_v1beta1.Gateway{gwObject, gwObjectIdentical}
   396  
   397  	vals := MultiMatchChecker{
   398  		Gateways: gws,
   399  	}.Check()
   400  
   401  	assert.NotEmpty(vals)
   402  	validgateway, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "validgateway"}]
   403  	assert.True(ok)
   404  
   405  	duplicatevalidgateway, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "duplicatevalidgateway"}]
   406  	assert.True(ok)
   407  
   408  	assert.Equal(2, len(validgateway.Checks))
   409  	assert.Equal("spec/servers[0]/hosts[0]", validgateway.Checks[0].Path)
   410  	assert.Equal("spec/servers[0]/hosts[1]", validgateway.Checks[1].Path)
   411  
   412  	assert.Equal(2, len(duplicatevalidgateway.Checks))
   413  	assert.Equal("spec/servers[0]/hosts[0]", duplicatevalidgateway.Checks[0].Path)
   414  	assert.Equal("spec/servers[0]/hosts[1]", duplicatevalidgateway.Checks[1].Path)
   415  }
   416  
   417  // One Host can be defined for multiple target namespaces without conflict
   418  func TestNoMatchOnDifferentTargetNamespaces(t *testing.T) {
   419  	conf := config.NewConfig()
   420  	config.Set(conf)
   421  
   422  	assert := assert.New(t)
   423  
   424  	gwObject := data.AddServerToGateway(data.CreateServer(
   425  		[]string{
   426  			"test1/example.com",
   427  			"test2/example.com",
   428  		}, 80, "http", "http"),
   429  
   430  		data.CreateEmptyGateway("shouldbevalid", "test", map[string]string{
   431  			"app": "ingressgateway",
   432  		}))
   433  
   434  	gws := []*networking_v1beta1.Gateway{gwObject}
   435  
   436  	vals := MultiMatchChecker{
   437  		Gateways: gws,
   438  	}.Check()
   439  
   440  	assert.Empty(vals)
   441  }
   442  
   443  // target Namespace '.' means that the Host is available in the Namespace of the Gateway resource
   444  func TestMatchOnSameTargetNamespace(t *testing.T) {
   445  	conf := config.NewConfig()
   446  	config.Set(conf)
   447  
   448  	assert := assert.New(t)
   449  
   450  	gwObject := data.AddServerToGateway(data.CreateServer(
   451  		[]string{
   452  			"test/example.com",
   453  			"./example.com",
   454  		}, 80, "http", "http"),
   455  
   456  		data.CreateEmptyGateway("shouldnotbevalid", "test", map[string]string{
   457  			"app": "ingressgateway",
   458  		}))
   459  
   460  	gws := []*networking_v1beta1.Gateway{gwObject}
   461  
   462  	vals := MultiMatchChecker{
   463  		Gateways: gws,
   464  	}.Check()
   465  
   466  	assert.NotEmpty(vals)
   467  	assert.Equal(1, len(vals))
   468  	validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "shouldnotbevalid"}]
   469  	assert.True(ok)
   470  	assert.True(validation.Valid)
   471  }
   472  
   473  // target Namespace * means that the Host is available in all namespaces
   474  func TestMatchOnWildcardTargetNamespace(t *testing.T) {
   475  	conf := config.NewConfig()
   476  	config.Set(conf)
   477  
   478  	assert := assert.New(t)
   479  
   480  	gwObject := data.AddServerToGateway(data.CreateServer(
   481  		[]string{
   482  			"test/example.com",
   483  			"*/example.com",
   484  		}, 80, "http", "http"),
   485  
   486  		data.CreateEmptyGateway("shouldnotbevalid", "test", map[string]string{
   487  			"app": "ingressgateway",
   488  		}))
   489  
   490  	gws := []*networking_v1beta1.Gateway{gwObject}
   491  
   492  	vals := MultiMatchChecker{
   493  		Gateways: gws,
   494  	}.Check()
   495  
   496  	assert.NotEmpty(vals)
   497  	assert.Equal(1, len(vals))
   498  	validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "shouldnotbevalid"}]
   499  	assert.True(ok)
   500  	assert.True(validation.Valid)
   501  }
   502  
   503  // having no target namespace set is the same as having * as target Namespace
   504  func TestMatchOnImplicitWildcardTargetNamespace(t *testing.T) {
   505  	conf := config.NewConfig()
   506  	config.Set(conf)
   507  
   508  	assert := assert.New(t)
   509  
   510  	gwObject := data.AddServerToGateway(data.CreateServer(
   511  		[]string{
   512  			"test/example.com",
   513  			"example.com",
   514  		}, 80, "http", "http"),
   515  
   516  		data.CreateEmptyGateway("shouldnotbevalid", "test", map[string]string{
   517  			"app": "ingressgateway",
   518  		}))
   519  
   520  	gws := []*networking_v1beta1.Gateway{gwObject}
   521  
   522  	vals := MultiMatchChecker{
   523  		Gateways: gws,
   524  	}.Check()
   525  
   526  	assert.NotEmpty(vals)
   527  	assert.Equal(1, len(vals))
   528  	validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "shouldnotbevalid"}]
   529  	assert.True(ok)
   530  	assert.True(validation.Valid)
   531  }