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

     1  package destinationrules
     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/kubernetes"
    11  	"github.com/kiali/kiali/models"
    12  	"github.com/kiali/kiali/tests/data"
    13  	"github.com/kiali/kiali/tests/testutils/validations"
    14  )
    15  
    16  func TestMultiHostMatchCorrect(t *testing.T) {
    17  	conf := config.NewConfig()
    18  	config.Set(conf)
    19  
    20  	assert := assert.New(t)
    21  
    22  	destinationRules := []*networking_v1beta1.DestinationRule{
    23  		data.CreateTestDestinationRule("test", "rule1", "host1"),
    24  		data.CreateTestDestinationRule("test", "rule2", "host2.test.svc.cluster.local"),
    25  	}
    26  
    27  	vals := MultiMatchChecker{
    28  		DestinationRules: destinationRules,
    29  	}.Check()
    30  
    31  	assert.Empty(vals)
    32  	validation, ok := vals[models.IstioValidationKey{ObjectType: "destinationrule", Namespace: "test", Name: "rule2"}]
    33  	assert.False(ok)
    34  	assert.Nil(validation)
    35  }
    36  
    37  func TestMultiHostMatchInvalid(t *testing.T) {
    38  	conf := config.NewConfig()
    39  	config.Set(conf)
    40  
    41  	assert := assert.New(t)
    42  
    43  	destinationRules := []*networking_v1beta1.DestinationRule{
    44  		data.CreateTestDestinationRule("test", "rule1", "host1"),
    45  		data.CreateTestDestinationRule("test", "rule2", "host1.test.svc.cluster.local"),
    46  		data.CreateTestDestinationRule("test", "rule3", "host1"),
    47  	}
    48  
    49  	vals := MultiMatchChecker{
    50  		DestinationRules: destinationRules,
    51  	}.Check()
    52  
    53  	assert.NotEmpty(vals)
    54  	assert.Equal(3, len(vals))
    55  
    56  	// Rule1 assertions
    57  	validationAssertion(assert, vals, "rule1", []string{"rule2", "rule3"})
    58  	validationAssertion(assert, vals, "rule2", []string{"rule1", "rule3"})
    59  	validationAssertion(assert, vals, "rule3", []string{"rule1", "rule2"})
    60  }
    61  
    62  func validationAssertion(assert *assert.Assertions, vals models.IstioValidations, drName string, refNames []string) {
    63  	validation, ok := vals[models.IstioValidationKey{ObjectType: "destinationrule", Namespace: "test", Name: drName}]
    64  	assert.True(ok)
    65  	assert.True(validation.Valid) // As long as it is warning, this is true
    66  	assert.NotEmpty(validation.Checks)
    67  	assert.Equal(models.WarningSeverity, validation.Checks[0].Severity)
    68  	assert.NoError(validations.ConfirmIstioCheckMessage("destinationrules.multimatch", validation.Checks[0]))
    69  
    70  	assert.NotEmpty(validation.References)
    71  	for _, refName := range refNames {
    72  		assert.Contains(validation.References,
    73  			models.IstioValidationKey{
    74  				ObjectType: "destinationrule",
    75  				Namespace:  "test",
    76  				Name:       refName,
    77  			},
    78  		)
    79  	}
    80  }
    81  
    82  func TestMultiHostMatchInvalidShortFormat(t *testing.T) {
    83  	conf := config.NewConfig()
    84  	config.Set(conf)
    85  
    86  	assert := assert.New(t)
    87  
    88  	destinationRules := []*networking_v1beta1.DestinationRule{
    89  		data.CreateTestDestinationRule("test", "rule1", "host1"),
    90  		data.CreateTestDestinationRule("test", "rule2", "host1.test"),
    91  	}
    92  
    93  	vals := MultiMatchChecker{
    94  		DestinationRules: destinationRules,
    95  	}.Check()
    96  
    97  	assert.NotEmpty(vals)
    98  	assert.Equal(2, len(vals))
    99  	validation, ok := vals[models.IstioValidationKey{ObjectType: "destinationrule", Namespace: "test", Name: "rule2"}]
   100  	assert.True(ok)
   101  	assert.True(validation.Valid) // As long as it is warning, this is true
   102  	assert.NotEmpty(validation.Checks)
   103  	assert.Equal(models.WarningSeverity, validation.Checks[0].Severity)
   104  	assert.NoError(validations.ConfirmIstioCheckMessage("destinationrules.multimatch", validation.Checks[0]))
   105  
   106  	assert.NotEmpty(validation.References)
   107  	assert.Equal("rule1", validation.References[0].Name)
   108  }
   109  
   110  func TestMultiHostMatchValidShortFormat(t *testing.T) {
   111  	conf := config.NewConfig()
   112  	config.Set(conf)
   113  
   114  	assert := assert.New(t)
   115  
   116  	destinationRules := []*networking_v1beta1.DestinationRule{
   117  		data.CreateTestDestinationRule("test", "rule1", "host1"),
   118  		data.CreateTestDestinationRule("test", "rule2", "host2.test"),
   119  	}
   120  
   121  	vals := MultiMatchChecker{
   122  		DestinationRules: destinationRules,
   123  	}.Check()
   124  
   125  	assert.Empty(vals)
   126  	validation, ok := vals[models.IstioValidationKey{ObjectType: "destinationrule", Namespace: "test", Name: "rule2"}]
   127  	assert.False(ok)
   128  	assert.Nil(validation)
   129  }
   130  
   131  func TestMultiHostMatchValidShortFormatDiffNamespace(t *testing.T) {
   132  	conf := config.NewConfig()
   133  	config.Set(conf)
   134  
   135  	assert := assert.New(t)
   136  
   137  	destinationRules := []*networking_v1beta1.DestinationRule{
   138  		data.CreateTestDestinationRule("test", "rule1", "host1"),
   139  		data.CreateTestDestinationRule("test", "rule2", "host2.bookinfo"),
   140  	}
   141  
   142  	vals := MultiMatchChecker{
   143  		Namespaces: models.Namespaces{
   144  			models.Namespace{Name: "bookinfo"},
   145  			models.Namespace{Name: "test"},
   146  		},
   147  		DestinationRules: destinationRules,
   148  	}.Check()
   149  
   150  	// MultiMatchChecker shouldn't fail if a host is in a different namespace
   151  	assert.Empty(vals)
   152  }
   153  
   154  func TestMultiHostMatchWildcardInvalid(t *testing.T) {
   155  	conf := config.NewConfig()
   156  	config.Set(conf)
   157  
   158  	assert := assert.New(t)
   159  
   160  	destinationRules := []*networking_v1beta1.DestinationRule{
   161  		data.CreateTestDestinationRule("test", "rule1", "host1"),
   162  		data.CreateTestDestinationRule("test", "rule2", "*.test.svc.cluster.local"),
   163  	}
   164  
   165  	vals := MultiMatchChecker{
   166  		DestinationRules: destinationRules,
   167  	}.Check()
   168  
   169  	assert.NotEmpty(vals)
   170  	validation, ok := vals[models.IstioValidationKey{ObjectType: "destinationrule", Namespace: "test", Name: "rule2"}]
   171  	assert.True(ok)
   172  	assert.True(validation.Valid) // As long as it is warning, this is true
   173  	assert.NotEmpty(validation.Checks)
   174  	assert.Equal(models.WarningSeverity, validation.Checks[0].Severity)
   175  
   176  	assert.NotEmpty(validation.References)
   177  	assert.Equal("rule1", validation.References[0].Name)
   178  
   179  	destinationRules = []*networking_v1beta1.DestinationRule{
   180  		data.CreateTestDestinationRule("test", "rule2", "*.test.svc.cluster.local"),
   181  		data.CreateTestDestinationRule("test", "rule1", "host1"),
   182  	}
   183  
   184  	vals = MultiMatchChecker{
   185  		DestinationRules: destinationRules,
   186  	}.Check()
   187  
   188  	assert.NotEmpty(vals)
   189  	validation, ok = vals[models.IstioValidationKey{ObjectType: "destinationrule", Namespace: "test", Name: "rule1"}]
   190  	assert.True(ok)
   191  	assert.True(validation.Valid) // As long as it is warning, this is true
   192  	assert.NotEmpty(validation.Checks)
   193  	assert.Equal(models.WarningSeverity, validation.Checks[0].Severity)
   194  
   195  	assert.NotEmpty(validation.References)
   196  	assert.Equal("rule2", validation.References[0].Name)
   197  }
   198  
   199  func TestMultiHostMatchBothWildcardInvalid(t *testing.T) {
   200  	conf := config.NewConfig()
   201  	config.Set(conf)
   202  
   203  	assert := assert.New(t)
   204  
   205  	destinationRules := []*networking_v1beta1.DestinationRule{
   206  		data.CreateTestDestinationRule("test", "rule1", "*"),
   207  		data.CreateTestDestinationRule("test", "rule2", "*.test.svc.cluster.local"),
   208  	}
   209  
   210  	vals := MultiMatchChecker{
   211  		DestinationRules: destinationRules,
   212  	}.Check()
   213  
   214  	assert.NotEmpty(vals)
   215  	validation, ok := vals[models.IstioValidationKey{ObjectType: "destinationrule", Namespace: "test", Name: "rule2"}]
   216  	assert.True(ok)
   217  	assert.True(validation.Valid) // As long as it is warning, this is true
   218  	assert.NotEmpty(validation.Checks)
   219  	assert.Equal(models.WarningSeverity, validation.Checks[0].Severity)
   220  
   221  	assert.NotEmpty(validation.References)
   222  	assert.Equal("rule1", validation.References[0].Name)
   223  
   224  	destinationRules = []*networking_v1beta1.DestinationRule{
   225  		data.CreateTestDestinationRule("test", "rule2", "*.test.svc.cluster.local"),
   226  		data.CreateTestDestinationRule("test", "rule1", "*"),
   227  	}
   228  
   229  	vals = MultiMatchChecker{
   230  		DestinationRules: destinationRules,
   231  	}.Check()
   232  
   233  	assert.NotEmpty(vals)
   234  	validation, ok = vals[models.IstioValidationKey{ObjectType: "destinationrule", Namespace: "test", Name: "rule1"}]
   235  	assert.True(ok)
   236  	assert.True(validation.Valid) // As long as it is warning, this is true
   237  	assert.NotEmpty(validation.Checks)
   238  	assert.Equal(models.WarningSeverity, validation.Checks[0].Severity)
   239  
   240  	assert.NotEmpty(validation.References)
   241  	assert.Equal("rule2", validation.References[0].Name)
   242  }
   243  
   244  func TestMultiHostMatchingMeshWideMTLSDestinationRule(t *testing.T) {
   245  	conf := config.NewConfig()
   246  	config.Set(conf)
   247  
   248  	assert := assert.New(t)
   249  
   250  	destinationRules := []*networking_v1beta1.DestinationRule{
   251  		data.CreateTestDestinationRule("test", "rule1", "host1"),
   252  		data.AddTrafficPolicyToDestinationRule(data.CreateMTLSTrafficPolicyForDestinationRules(),
   253  			data.CreateTestDestinationRule("test", "rule2", "*.local")),
   254  	}
   255  
   256  	vals := MultiMatchChecker{
   257  		DestinationRules: destinationRules,
   258  	}.Check()
   259  
   260  	assert.Empty(vals)
   261  	validation, ok := vals[models.IstioValidationKey{ObjectType: "destinationrule", Namespace: "test", Name: "rule2"}]
   262  	assert.False(ok)
   263  	assert.Nil(validation)
   264  }
   265  
   266  func TestMultiHostMatchingNamespaceWideMTLSDestinationRule(t *testing.T) {
   267  	conf := config.NewConfig()
   268  	config.Set(conf)
   269  
   270  	assert := assert.New(t)
   271  
   272  	destinationRules := []*networking_v1beta1.DestinationRule{
   273  		data.CreateTestDestinationRule("test", "rule1", "host1"),
   274  		data.AddTrafficPolicyToDestinationRule(data.CreateMTLSTrafficPolicyForDestinationRules(),
   275  			data.CreateTestDestinationRule("test", "rule2", "*.test.svc.cluster.local")),
   276  	}
   277  
   278  	vals := MultiMatchChecker{
   279  		DestinationRules: destinationRules,
   280  	}.Check()
   281  
   282  	assert.Empty(vals)
   283  	validation, ok := vals[models.IstioValidationKey{ObjectType: "destinationrule", Namespace: "test", Name: "rule2"}]
   284  	assert.False(ok)
   285  	assert.Nil(validation)
   286  }
   287  
   288  func TestMultiHostMatchDifferentSubsets(t *testing.T) {
   289  	conf := config.NewConfig()
   290  	config.Set(conf)
   291  
   292  	assert := assert.New(t)
   293  
   294  	destinationRules := []*networking_v1beta1.DestinationRule{
   295  		data.AddSubsetToDestinationRule(data.CreateSubset("v1", "v1"),
   296  			data.AddSubsetToDestinationRule(data.CreateSubset("v2", "v2"), data.CreateEmptyDestinationRule("test", "rule1", "host1"))),
   297  		data.AddSubsetToDestinationRule(data.CreateSubset("v3", "v3"),
   298  			data.AddSubsetToDestinationRule(data.CreateSubset("v4", "v4"), data.CreateEmptyDestinationRule("test", "rule2", "host1"))),
   299  	}
   300  
   301  	vals := MultiMatchChecker{
   302  		DestinationRules: destinationRules,
   303  	}.Check()
   304  
   305  	assert.Empty(vals)
   306  
   307  	destinationRules = append(destinationRules,
   308  		data.AddSubsetToDestinationRule(data.CreateSubset("v1", "v1"),
   309  			data.AddSubsetToDestinationRule(data.CreateSubset("v5", "v5"), data.CreateEmptyDestinationRule("test", "rule5", "*.test.svc.cluster.local"))),
   310  	)
   311  
   312  	vals = MultiMatchChecker{
   313  		DestinationRules: destinationRules,
   314  	}.Check()
   315  
   316  	assert.NotEmpty(vals)
   317  }
   318  
   319  func TestReviewsExample(t *testing.T) {
   320  	conf := config.NewConfig()
   321  	config.Set(conf)
   322  
   323  	assert := assert.New(t)
   324  
   325  	destinationRules := []*networking_v1beta1.DestinationRule{
   326  		data.AddSubsetToDestinationRule(data.CreateSubset("v2", "v2"),
   327  			data.AddSubsetToDestinationRule(data.CreateSubset("v3", "v3"), data.CreateEmptyDestinationRule("bookinfo", "reviews", "reviews"))),
   328  		data.AddSubsetToDestinationRule(data.CreateSubset("v1", "v1"), data.CreateEmptyDestinationRule("bookinfo", "reviews2", "reviews")),
   329  	}
   330  
   331  	vals := MultiMatchChecker{
   332  		DestinationRules: destinationRules,
   333  	}.Check()
   334  
   335  	assert.Empty(vals)
   336  
   337  	allMatch := data.CreateEmptyDestinationRule("bookinfo", "reviews3", "reviews")
   338  	destinationRules = append(destinationRules, allMatch)
   339  
   340  	vals = MultiMatchChecker{
   341  		DestinationRules: destinationRules,
   342  	}.Check()
   343  
   344  	assert.NotEmpty(vals)
   345  	assert.Equal(3, len(vals))
   346  	validation, ok := vals[models.IstioValidationKey{ObjectType: "destinationrule", Namespace: "bookinfo", Name: "reviews3"}]
   347  	assert.True(ok)
   348  	assert.True(validation.Valid)
   349  	assert.NotEmpty(validation.Checks)
   350  	assert.Equal(models.WarningSeverity, validation.Checks[0].Severity)
   351  	assert.Equal(1, len(validation.Checks))
   352  
   353  	assert.Equal(2, len(validation.References)) // Both reviews and reviews2 is faulty
   354  }
   355  
   356  func TestMultiServiceEntry(t *testing.T) {
   357  	conf := config.NewConfig()
   358  	config.Set(conf)
   359  
   360  	assert := assert.New(t)
   361  
   362  	seA := data.AddPortDefinitionToServiceEntry(data.CreateEmptyServicePortDefinition(443, "https", "TLS"), data.CreateEmptyMeshExternalServiceEntry("service-a", "test", []string{"api.service_a.com"}))
   363  	seB := data.AddPortDefinitionToServiceEntry(data.CreateEmptyServicePortDefinition(443, "https", "TLS"), data.CreateEmptyMeshExternalServiceEntry("service-b", "test", []string{"api.service_b.com"}))
   364  
   365  	drA := data.CreateEmptyDestinationRule("test", "service-a", "api.service_a.com")
   366  	drB := data.CreateEmptyDestinationRule("test", "service-b", "api.service_b.com")
   367  
   368  	vals := MultiMatchChecker{
   369  		DestinationRules: []*networking_v1beta1.DestinationRule{drA, drB},
   370  		ServiceEntries:   kubernetes.ServiceEntryHostnames([]*networking_v1beta1.ServiceEntry{seA, seB}),
   371  	}.Check()
   372  
   373  	assert.Empty(vals)
   374  }
   375  
   376  func TestMultiServiceEntryInvalid(t *testing.T) {
   377  	conf := config.NewConfig()
   378  	config.Set(conf)
   379  
   380  	assert := assert.New(t)
   381  
   382  	seA := data.AddPortDefinitionToServiceEntry(data.CreateEmptyServicePortDefinition(443, "https", "TLS"), data.CreateEmptyMeshExternalServiceEntry("service-a", "test", []string{"api.service_a.com"}))
   383  
   384  	drA := data.CreateEmptyDestinationRule("test", "service-a", "api.service_a.com")
   385  	drB := data.CreateEmptyDestinationRule("test", "service-a2", "api.service_a.com")
   386  
   387  	vals := MultiMatchChecker{
   388  		DestinationRules: []*networking_v1beta1.DestinationRule{drA, drB},
   389  		ServiceEntries:   kubernetes.ServiceEntryHostnames([]*networking_v1beta1.ServiceEntry{seA}),
   390  	}.Check()
   391  
   392  	assert.NotEmpty(vals)
   393  	assert.Equal(2, len(vals))
   394  	validation, ok := vals[models.IstioValidationKey{ObjectType: "destinationrule", Namespace: "test", Name: "service-a2"}]
   395  	assert.True(ok)
   396  	assert.True(validation.Valid)
   397  	assert.NotEmpty(validation.Checks)
   398  	assert.Equal(models.WarningSeverity, validation.Checks[0].Severity)
   399  	assert.Equal(1, len(validation.Checks))
   400  
   401  	assert.Equal(1, len(validation.References)) // Both reviews and reviews2 is faulty
   402  }