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

     1  package appender
     2  
     3  import (
     4  	"github.com/kiali/kiali/config"
     5  	"github.com/kiali/kiali/graph"
     6  	"github.com/kiali/kiali/log"
     7  	"github.com/kiali/kiali/models"
     8  )
     9  
    10  const IdleNodeAppenderName = "idleNode"
    11  
    12  // IdleNodeAppender looks for services that have never seen request traffic.  It adds nodes to represent the
    13  // idle/unused definitions.  The added node types depend on the graph type and/or labeling on the definition.
    14  // Name: idleNode
    15  type IdleNodeAppender struct {
    16  	GraphType          string
    17  	InjectServiceNodes bool // This appender adds idle services only when service nodes are injected or graphType=service
    18  	IsNodeGraph        bool // This appender does not operate on node detail graphs because we want to focus on the specific node.
    19  }
    20  
    21  // Name implements Appender
    22  func (a IdleNodeAppender) Name() string {
    23  	return IdleNodeAppenderName
    24  }
    25  
    26  // IsFinalizer implements Appender
    27  func (a IdleNodeAppender) IsFinalizer() bool {
    28  	return false
    29  }
    30  
    31  // AppendGraph implements Appender
    32  func (a IdleNodeAppender) AppendGraph(trafficMap graph.TrafficMap, globalInfo *graph.AppenderGlobalInfo, namespaceInfo *graph.AppenderNamespaceInfo) {
    33  	if a.IsNodeGraph {
    34  		return
    35  	}
    36  
    37  	serviceLists := map[string]*models.ServiceList{}
    38  	workloadLists := map[string]*models.WorkloadList{}
    39  
    40  	if a.GraphType != graph.GraphTypeService {
    41  		workloadLists = getWorkloadLists(nil, namespaceInfo.Namespace, globalInfo)
    42  	}
    43  
    44  	if a.GraphType == graph.GraphTypeService || a.InjectServiceNodes {
    45  		serviceLists = getServiceLists(nil, namespaceInfo.Namespace, globalInfo)
    46  	}
    47  
    48  	a.addIdleNodes(trafficMap, namespaceInfo.Namespace, serviceLists, workloadLists)
    49  }
    50  
    51  func (a IdleNodeAppender) addIdleNodes(trafficMap graph.TrafficMap, namespace string, serviceLists map[string]*models.ServiceList, workloadLists map[string]*models.WorkloadList) {
    52  	idleNodeTrafficMap := a.buildIdleNodeTrafficMap(trafficMap, namespace, serviceLists, workloadLists)
    53  
    54  	// Integrate the idle nodes into the existing traffic map
    55  	for id, idleNode := range idleNodeTrafficMap {
    56  		trafficMap[id] = idleNode
    57  	}
    58  }
    59  
    60  func (a IdleNodeAppender) buildIdleNodeTrafficMap(trafficMap graph.TrafficMap, namespace string, serviceLists map[string]*models.ServiceList, workloadLists map[string]*models.WorkloadList) graph.TrafficMap {
    61  	idleNodeTrafficMap := graph.NewTrafficMap()
    62  
    63  	for cluster, serviceList := range serviceLists {
    64  		for _, s := range serviceList.Services {
    65  			id, nodeType, _ := graph.Id(cluster, namespace, s.Name, "", "", "", "", a.GraphType)
    66  			if _, found := trafficMap[id]; !found {
    67  				if _, found = idleNodeTrafficMap[id]; !found {
    68  					log.Tracef("Adding idle node for service [%s]", s.Name)
    69  					node := graph.NewNodeExplicit(id, cluster, namespace, "", "", "", s.Name, nodeType, a.GraphType)
    70  					// note: we don't know what the protocol really should be, http is most common, it's a dead edge anyway
    71  					node.Metadata = graph.Metadata{"httpIn": 0.0, "httpOut": 0.0, graph.IsIdle: true}
    72  					idleNodeTrafficMap[id] = node
    73  				}
    74  			}
    75  		}
    76  
    77  		cfg := config.Get()
    78  		appLabel := cfg.IstioLabels.AppLabelName
    79  		versionLabel := cfg.IstioLabels.VersionLabelName
    80  		if workloadList, ok := workloadLists[cluster]; ok {
    81  			for _, w := range workloadList.Workloads {
    82  				labels := w.Labels
    83  				app := graph.Unknown
    84  				version := graph.Unknown
    85  				if v, ok := labels[appLabel]; ok {
    86  					app = v
    87  				}
    88  				if v, ok := labels[versionLabel]; ok {
    89  					version = v
    90  				}
    91  				id, nodeType, _ := graph.Id(cluster, "", "", namespace, w.Name, app, version, a.GraphType)
    92  				if _, found := trafficMap[id]; !found {
    93  					if _, found = idleNodeTrafficMap[id]; !found {
    94  						log.Tracef("Adding idle node for workload [%s] with labels [%v]", w.Name, labels)
    95  						node := graph.NewNodeExplicit(id, cluster, namespace, w.Name, app, version, "", nodeType, a.GraphType)
    96  						// note: we don't know what the protocol really should be, http is most common, it's a dead edge anyway
    97  						node.Metadata = graph.Metadata{"httpIn": 0.0, "httpOut": 0.0, graph.IsIdle: true}
    98  						idleNodeTrafficMap[id] = node
    99  					}
   100  				}
   101  			}
   102  		}
   103  	}
   104  	return idleNodeTrafficMap
   105  }