github.com/kiali/kiali@v1.84.0/graph/telemetry/istio/appender/dead_node_test.go (about)

     1  package appender
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	apps_v1 "k8s.io/api/apps/v1"
     9  	core_v1 "k8s.io/api/core/v1"
    10  	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    11  
    12  	"github.com/kiali/kiali/business"
    13  	"github.com/kiali/kiali/config"
    14  	"github.com/kiali/kiali/graph"
    15  	"github.com/kiali/kiali/kubernetes"
    16  	"github.com/kiali/kiali/kubernetes/kubetest"
    17  )
    18  
    19  func setupWorkloads(t *testing.T) *business.Layer {
    20  	conf := config.NewConfig()
    21  	conf.KubernetesConfig.ClusterName = config.DefaultClusterID
    22  	config.Set(conf)
    23  
    24  	k8s := kubetest.NewFakeK8sClient(
    25  		&core_v1.Namespace{ObjectMeta: meta_v1.ObjectMeta{Name: "testNamespace"}},
    26  		&apps_v1.Deployment{
    27  			ObjectMeta: meta_v1.ObjectMeta{
    28  				Name:      "testPodsWithTraffic-v1",
    29  				Namespace: "testNamespace",
    30  			},
    31  			Spec: apps_v1.DeploymentSpec{
    32  				Template: core_v1.PodTemplateSpec{
    33  					ObjectMeta: meta_v1.ObjectMeta{
    34  						Labels: map[string]string{"app": "testPodsWithTraffic", "version": "v1"},
    35  					},
    36  				},
    37  			},
    38  		},
    39  		&apps_v1.Deployment{
    40  			ObjectMeta: meta_v1.ObjectMeta{
    41  				Name:      "testPodsNoTraffic-v1",
    42  				Namespace: "testNamespace",
    43  			},
    44  			Spec: apps_v1.DeploymentSpec{
    45  				Template: core_v1.PodTemplateSpec{
    46  					ObjectMeta: meta_v1.ObjectMeta{
    47  						Labels: map[string]string{"app": "testPodsNoTraffic", "version": "v1"},
    48  					},
    49  				},
    50  			},
    51  		},
    52  		&apps_v1.Deployment{
    53  			ObjectMeta: meta_v1.ObjectMeta{
    54  				Name:      "testNoPodsWithTraffic-v1",
    55  				Namespace: "testNamespace",
    56  			},
    57  			Spec: apps_v1.DeploymentSpec{
    58  				Template: core_v1.PodTemplateSpec{
    59  					ObjectMeta: meta_v1.ObjectMeta{
    60  						Labels: map[string]string{"app": "testNoPodsWithTraffic", "version": "v1"},
    61  					},
    62  				},
    63  			},
    64  		},
    65  		&apps_v1.Deployment{
    66  			ObjectMeta: meta_v1.ObjectMeta{
    67  				Name:      "testNoPodsNoTraffic-v1",
    68  				Namespace: "testNamespace",
    69  			},
    70  			Spec: apps_v1.DeploymentSpec{
    71  				Template: core_v1.PodTemplateSpec{
    72  					ObjectMeta: meta_v1.ObjectMeta{
    73  						Labels: map[string]string{"app": "testNoPodsNoTraffic", "version": "v1"},
    74  					},
    75  				},
    76  			},
    77  		},
    78  		&core_v1.Pod{
    79  			ObjectMeta: meta_v1.ObjectMeta{
    80  				Name:      "testPodsWithTraffic-v1-1234",
    81  				Namespace: "testNamespace",
    82  				Labels:    map[string]string{"app": "testPodsWithTraffic", "version": "v1"},
    83  			},
    84  			Status: core_v1.PodStatus{
    85  				Message: "foo",
    86  			},
    87  		},
    88  		&core_v1.Pod{
    89  			ObjectMeta: meta_v1.ObjectMeta{
    90  				Name:      "testPodsNoTraffic-v1-1234",
    91  				Namespace: "testNamespace",
    92  				Labels:    map[string]string{"app": "testPodsNoTraffic", "version": "v1"},
    93  			},
    94  			Status: core_v1.PodStatus{
    95  				Message: "foo",
    96  			},
    97  		},
    98  	)
    99  
   100  	business.SetupBusinessLayer(t, k8s, *conf)
   101  
   102  	k8sclients := make(map[string]kubernetes.ClientInterface)
   103  	k8sclients[config.DefaultClusterID] = k8s
   104  	businessLayer := business.NewWithBackends(k8sclients, k8sclients, nil, nil)
   105  	return businessLayer
   106  }
   107  
   108  func TestDeadNode(t *testing.T) {
   109  	assert := assert.New(t)
   110  
   111  	businessLayer := setupWorkloads(t)
   112  	trafficMap := testTrafficMap()
   113  
   114  	assert.Equal(12, len(trafficMap))
   115  	unknownID, _, _ := graph.Id(config.DefaultClusterID, graph.Unknown, "", graph.Unknown, graph.Unknown, graph.Unknown, graph.Unknown, graph.GraphTypeVersionedApp)
   116  	unknownNode, found := trafficMap[unknownID]
   117  	assert.Equal(true, found)
   118  	assert.Equal(graph.Unknown, unknownNode.Workload)
   119  	assert.Equal(10, len(unknownNode.Edges))
   120  
   121  	ingressID, _, _ := graph.Id(config.DefaultClusterID, graph.Unknown, "", "istio-system", "istio-ingressgateway", "istio-ingressgateway", graph.Unknown, graph.GraphTypeVersionedApp)
   122  	ingressNode, found := trafficMap[ingressID]
   123  	assert.Equal(true, found)
   124  	assert.Equal("istio-ingressgateway", ingressNode.Workload)
   125  	assert.Equal(10, len(ingressNode.Edges))
   126  
   127  	globalInfo := graph.NewAppenderGlobalInfo()
   128  	globalInfo.Business = businessLayer
   129  	namespaceInfo := graph.NewAppenderNamespaceInfo("testNamespace")
   130  
   131  	a := DeadNodeAppender{
   132  		AccessibleNamespaces: map[string]*graph.AccessibleNamespace{
   133  			fmt.Sprintf("%s:testNamespace", config.DefaultClusterID): {
   134  				Cluster: config.DefaultClusterID,
   135  				Name:    "testNamespace",
   136  			},
   137  			fmt.Sprintf("%s:istio-system", config.DefaultClusterID): {
   138  				Cluster: config.DefaultClusterID,
   139  				Name:    "istio-system",
   140  			},
   141  		},
   142  	}
   143  	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
   144  
   145  	assert.Equal(10, len(trafficMap))
   146  
   147  	_, found = trafficMap[unknownID]
   148  	assert.Equal(false, found)
   149  
   150  	ingressNode, found = trafficMap[ingressID]
   151  	assert.Equal(true, found)
   152  	assert.Equal(9, len(ingressNode.Edges))
   153  
   154  	assert.Equal("testPodsWithTraffic-v1", ingressNode.Edges[0].Dest.Workload)
   155  	assert.Equal("testPodsNoTraffic-v1", ingressNode.Edges[1].Dest.Workload)
   156  	assert.Equal("testNoPodsWithTraffic-v1", ingressNode.Edges[2].Dest.Workload)
   157  	assert.Equal("testNoPodsNoTraffic-v1", ingressNode.Edges[3].Dest.Workload)
   158  	assert.Equal("testNoDeploymentWithTraffic-v1", ingressNode.Edges[4].Dest.Workload)
   159  	assert.Equal("testNodeWithTcpSentTraffic-v1", ingressNode.Edges[5].Dest.Workload)
   160  	assert.Equal("testNodeWithTcpSentOutTraffic-v1", ingressNode.Edges[6].Dest.Workload)
   161  
   162  	id, _, _ := graph.Id(config.DefaultClusterID, "testNamespace", "testNoPodsNoTraffic", "testNamespace", "testNoPodsNoTraffic-v1", "testNoPodsNoTraffic", "v1", graph.GraphTypeVersionedApp)
   163  	noPodsNoTraffic, ok := trafficMap[id]
   164  	assert.Equal(true, ok)
   165  	isDead, ok := noPodsNoTraffic.Metadata[graph.IsDead]
   166  	assert.Equal(true, ok)
   167  	assert.Equal(true, isDead)
   168  
   169  	// Check that external services are not removed
   170  	id, _, _ = graph.Id(config.DefaultClusterID, "testNamespace", "egress.io", "testNamespace", "", "", "", graph.GraphTypeVersionedApp)
   171  	_, okExternal := trafficMap[id]
   172  	assert.Equal(true, okExternal)
   173  }
   174  
   175  func testTrafficMap() map[string]*graph.Node {
   176  	trafficMap := make(map[string]*graph.Node)
   177  
   178  	n0, _ := graph.NewNode(config.DefaultClusterID, graph.Unknown, "", graph.Unknown, graph.Unknown, graph.Unknown, graph.Unknown, graph.GraphTypeVersionedApp)
   179  
   180  	n00, _ := graph.NewNode(config.DefaultClusterID, graph.Unknown, "", "istio-system", "istio-ingressgateway", "istio-ingressgateway", graph.Unknown, graph.GraphTypeVersionedApp)
   181  	n00.Metadata["httpOut"] = 4.8
   182  
   183  	n1, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "testPodsWithTraffic", "testNamespace", "testPodsWithTraffic-v1", "testPodsWithTraffic", "v1", graph.GraphTypeVersionedApp)
   184  	n1.Metadata["httpIn"] = 0.8
   185  
   186  	n2, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "testPodsNoTraffic", "testNamespace", "testPodsNoTraffic-v1", "testPodsNoTraffic", "v1", graph.GraphTypeVersionedApp)
   187  
   188  	n3, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "testNoPodsWithTraffic", "testNamespace", "testNoPodsWithTraffic-v1", "testNoPodsWithTraffic", "v1", graph.GraphTypeVersionedApp)
   189  	n3.Metadata["httpIn"] = 0.8
   190  
   191  	n4, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "testNoPodsNoTraffic", "testNamespace", "testNoPodsNoTraffic-v1", "testNoPodsNoTraffic", "v1", graph.GraphTypeVersionedApp)
   192  
   193  	n5, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "testNoDeploymentWithTraffic", "testNamespace", "testNoDeploymentWithTraffic-v1", "testNoDeploymentWithTraffic", "v1", graph.GraphTypeVersionedApp)
   194  	n5.Metadata["httpIn"] = 0.8
   195  
   196  	n6, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "testNoDeploymentNoTraffic", "testNamespace", "testNoDeploymentNoTraffic-v1", "testNoDeploymentNoTraffic", "v1", graph.GraphTypeVersionedApp)
   197  
   198  	n7, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "testNodeWithTcpSentTraffic", "testNamespace", "testNodeWithTcpSentTraffic-v1", "testNodeWithTcpSentTraffic", "v1", graph.GraphTypeVersionedApp)
   199  	n7.Metadata["tcpIn"] = 74.1
   200  
   201  	n8, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "testNodeWithTcpSentOutTraffic", "testNamespace", "testNodeWithTcpSentOutTraffic-v1", "testNodeWithTcpSentOutTraffic", "v1", graph.GraphTypeVersionedApp)
   202  	n8.Metadata["tcpOut"] = 74.1
   203  
   204  	n9, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "egress.io", "testNamespace", "", "", "", graph.GraphTypeVersionedApp)
   205  	n9.Metadata["httpIn"] = 0.8
   206  	n9.Metadata[graph.IsServiceEntry] = &graph.SEInfo{
   207  		Location: "MESH_EXTERNAL",
   208  	}
   209  
   210  	n10, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "egress.not.defined", "testNamespace", "", "", "", graph.GraphTypeVersionedApp)
   211  	n10.Metadata["httpIn"] = 0.8
   212  
   213  	trafficMap[n0.ID] = n0
   214  	trafficMap[n00.ID] = n00
   215  	trafficMap[n1.ID] = n1
   216  	trafficMap[n2.ID] = n2
   217  	trafficMap[n3.ID] = n3
   218  	trafficMap[n4.ID] = n4
   219  	trafficMap[n5.ID] = n5
   220  	trafficMap[n6.ID] = n6
   221  	trafficMap[n7.ID] = n7
   222  	trafficMap[n8.ID] = n8
   223  	trafficMap[n9.ID] = n9
   224  	trafficMap[n10.ID] = n10
   225  
   226  	n0.AddEdge(n1)
   227  	e := n00.AddEdge(n1)
   228  	e.Metadata["http"] = 0.8
   229  
   230  	n0.AddEdge(n2)
   231  	e = n00.AddEdge(n2)
   232  	e.Metadata["http"] = 0.8
   233  
   234  	n0.AddEdge(n3)
   235  	e = n00.AddEdge(n3)
   236  	e.Metadata["http"] = 0.8
   237  
   238  	n0.AddEdge(n4)
   239  	e = n00.AddEdge(n4)
   240  	e.Metadata["http"] = 0.0
   241  
   242  	n0.AddEdge(n5)
   243  	e = n00.AddEdge(n5)
   244  	e.Metadata["http"] = 0.8
   245  
   246  	n0.AddEdge(n6)
   247  	e = n00.AddEdge(n6)
   248  	e.Metadata["http"] = 0.0
   249  
   250  	n0.AddEdge(n7)
   251  	e = n00.AddEdge(n7)
   252  	e.Metadata["tcp"] = 74.1
   253  
   254  	n0.AddEdge(n8)
   255  	e = n00.AddEdge(n8)
   256  	e.Metadata["tcp"] = 74.1
   257  
   258  	n0.AddEdge(n9)
   259  	e = n00.AddEdge(n9)
   260  	e.Metadata["http"] = 0.8
   261  
   262  	n0.AddEdge(n10)
   263  	e = n00.AddEdge(n10)
   264  	e.Metadata["http"] = 0.8
   265  
   266  	return trafficMap
   267  }
   268  
   269  func TestDeadNodeIssue2783(t *testing.T) {
   270  	assert := assert.New(t)
   271  
   272  	businessLayer := setupWorkloads(t)
   273  	trafficMap := testTrafficMapIssue2783()
   274  
   275  	assert.Equal(3, len(trafficMap))
   276  	aID, _, _ := graph.Id(config.DefaultClusterID, "testNamespace", "a", "testNamespace", "a-v1", "a", "v1", graph.GraphTypeVersionedApp)
   277  	aNode, found := trafficMap[aID]
   278  	assert.Equal(true, found)
   279  	assert.Equal(1, len(aNode.Edges))
   280  
   281  	bSvcID, _, _ := graph.Id(config.DefaultClusterID, "testNamespace", "b", graph.Unknown, graph.Unknown, graph.Unknown, graph.Unknown, graph.GraphTypeVersionedApp)
   282  	bSvcNode, found := trafficMap[bSvcID]
   283  	assert.Equal(true, found)
   284  	assert.Equal(1, len(bSvcNode.Edges))
   285  
   286  	bID, _, _ := graph.Id(config.DefaultClusterID, "testNamespace", "b", "testNamespace", "b-v1", "b", "v1", graph.GraphTypeVersionedApp)
   287  	bNode, found := trafficMap[bID]
   288  	assert.Equal(true, found)
   289  	assert.Equal(0, len(bNode.Edges))
   290  
   291  	globalInfo := graph.NewAppenderGlobalInfo()
   292  	globalInfo.Business = businessLayer
   293  	namespaceInfo := graph.NewAppenderNamespaceInfo("testNamespace")
   294  
   295  	a := DeadNodeAppender{
   296  		AccessibleNamespaces: map[string]*graph.AccessibleNamespace{
   297  			fmt.Sprintf("%s:testNamespace", config.DefaultClusterID): {
   298  				Cluster: config.DefaultClusterID,
   299  				Name:    "testNamespace",
   300  			},
   301  		},
   302  	}
   303  	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
   304  
   305  	assert.Equal(0, len(trafficMap))
   306  }
   307  
   308  // testTrafficMapIssue2783() ensures that zero request traffic does not leave behind an injected service node.
   309  func testTrafficMapIssue2783() map[string]*graph.Node {
   310  	trafficMap := make(map[string]*graph.Node)
   311  
   312  	n0, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "a", "testNamespace", "a-v1", "a", "v1", graph.GraphTypeVersionedApp)
   313  
   314  	n1, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "b", graph.Unknown, graph.Unknown, graph.Unknown, graph.Unknown, graph.GraphTypeVersionedApp)
   315  
   316  	n2, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "b", "testNamespace", "b-v1", "b", "v1", graph.GraphTypeVersionedApp)
   317  
   318  	trafficMap[n0.ID] = n0
   319  	trafficMap[n1.ID] = n1
   320  	trafficMap[n2.ID] = n2
   321  
   322  	n0.AddEdge(n1)
   323  	n1.AddEdge(n2)
   324  
   325  	return trafficMap
   326  }
   327  
   328  func TestDeadNodeIssue2982(t *testing.T) {
   329  	assert := assert.New(t)
   330  
   331  	businessLayer := setupWorkloads(t)
   332  	trafficMap := testTrafficMapIssue2982()
   333  
   334  	assert.Equal(3, len(trafficMap))
   335  	aID, _, _ := graph.Id(config.DefaultClusterID, "testNamespace", "testPodsWithTraffic", "testNamespace", "testPodsWithTraffic-v1", "a", "v1", graph.GraphTypeVersionedApp)
   336  	aNode, found := trafficMap[aID]
   337  	assert.Equal(true, found)
   338  	assert.Equal(1, len(aNode.Edges))
   339  
   340  	bSvcID, _, _ := graph.Id(config.DefaultClusterID, "testNamespace", "b", graph.Unknown, graph.Unknown, graph.Unknown, graph.Unknown, graph.GraphTypeVersionedApp)
   341  	bSvcNode, found := trafficMap[bSvcID]
   342  	assert.Equal(true, found)
   343  	assert.Equal(1, len(bSvcNode.Edges))
   344  
   345  	bID, _, _ := graph.Id(config.DefaultClusterID, "testNamespace", "b", "testNamespace", "b-v1", "b", "v1", graph.GraphTypeVersionedApp)
   346  	bNode, found := trafficMap[bID]
   347  	assert.Equal(true, found)
   348  	assert.Equal(0, len(bNode.Edges))
   349  
   350  	globalInfo := graph.NewAppenderGlobalInfo()
   351  	globalInfo.Business = businessLayer
   352  	namespaceInfo := graph.NewAppenderNamespaceInfo("testNamespace")
   353  
   354  	a := DeadNodeAppender{
   355  		AccessibleNamespaces: map[string]*graph.AccessibleNamespace{
   356  			fmt.Sprintf("%s:testNamespace", config.DefaultClusterID): {
   357  				Cluster: config.DefaultClusterID,
   358  				Name:    "testNamespace",
   359  			},
   360  		},
   361  	}
   362  	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
   363  
   364  	assert.Equal(1, len(trafficMap))
   365  	_, found = trafficMap[aID]
   366  	assert.Equal(true, found)
   367  }
   368  
   369  // testTrafficMapIssue2783() ensures that zero request traffic does not leave behind an injected service node.
   370  func testTrafficMapIssue2982() map[string]*graph.Node {
   371  	trafficMap := make(map[string]*graph.Node)
   372  
   373  	n0, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "testPodsWithTraffic", "testNamespace", "testPodsWithTraffic-v1", "testPodsWithTraffic", "v1", graph.GraphTypeVersionedApp)
   374  	n0.Metadata["httpIn"] = 0.8
   375  
   376  	n1, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "b", graph.Unknown, graph.Unknown, graph.Unknown, graph.Unknown, graph.GraphTypeVersionedApp)
   377  
   378  	n2, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "b", "testNamespace", "b-v1", "b", "v1", graph.GraphTypeVersionedApp)
   379  
   380  	trafficMap[n0.ID] = n0
   381  	trafficMap[n1.ID] = n1
   382  	trafficMap[n2.ID] = n2
   383  
   384  	n0.AddEdge(n1)
   385  	n1.AddEdge(n2)
   386  
   387  	return trafficMap
   388  }
   389  
   390  func TestDeadNodeIssue7179(t *testing.T) {
   391  	assert := assert.New(t)
   392  
   393  	businessLayer := setupWorkloads(t)
   394  	trafficMap := testTrafficMapIssue7179()
   395  
   396  	assert.Equal(2, len(trafficMap))
   397  	aID, _, _ := graph.Id(config.DefaultClusterID, "testNamespace", "testPodsWithTraffic", "testNamespace", "testPodsWithTraffic-v1", "a", "v1", graph.GraphTypeVersionedApp)
   398  	aNode, found := trafficMap[aID]
   399  	assert.Equal(true, found)
   400  	assert.Equal(1, len(aNode.Edges))
   401  
   402  	bID, _, _ := graph.Id("InaccessibleCluster", "testNamespace", "noTraffic", "testNamespace", "noTraffic-v1", "b", "v1", graph.GraphTypeVersionedApp)
   403  	bNode, found := trafficMap[bID]
   404  	assert.Equal(true, found)
   405  	assert.Equal(0, len(bNode.Edges))
   406  
   407  	globalInfo := graph.NewAppenderGlobalInfo()
   408  	globalInfo.Business = businessLayer
   409  	namespaceInfo := graph.NewAppenderNamespaceInfo("testNamespace")
   410  
   411  	a := DeadNodeAppender{
   412  		AccessibleNamespaces: map[string]*graph.AccessibleNamespace{
   413  			fmt.Sprintf("%s:testNamespace", config.DefaultClusterID): {
   414  				Cluster: config.DefaultClusterID,
   415  				Name:    "testNamespace",
   416  			},
   417  		},
   418  	}
   419  	a.AppendGraph(trafficMap, globalInfo, namespaceInfo)
   420  
   421  	assert.Equal(2, len(trafficMap))
   422  	_, found = trafficMap[aID]
   423  	assert.Equal(true, found)
   424  	_, found = trafficMap[bID]
   425  	assert.Equal(true, found)
   426  }
   427  
   428  // testTrafficMapIssue7179() ensures we assume that innaccessible workloads are not dead.
   429  func testTrafficMapIssue7179() map[string]*graph.Node {
   430  	trafficMap := make(map[string]*graph.Node)
   431  
   432  	n0, _ := graph.NewNode(config.DefaultClusterID, "testNamespace", "testPodsWithTraffic", "testNamespace", "testPodsWithTraffic-v1", "testPodsWithTraffic", "v1", graph.GraphTypeVersionedApp)
   433  	n0.Metadata["httpIn"] = 0.8
   434  
   435  	n1, _ := graph.NewNode("InaccessibleCluster", "testNamespace", "noTraffic", "testNamespace", "noTraffic-v1", "noTraffic", "v1", graph.GraphTypeVersionedApp)
   436  
   437  	trafficMap[n0.ID] = n0
   438  	trafficMap[n1.ID] = n1
   439  
   440  	n0.AddEdge(n1)
   441  
   442  	return trafficMap
   443  }