networkinsightgraph.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. package opencost
  2. import (
  3. "fmt"
  4. "github.com/opencost/opencost/core/pkg/log"
  5. )
  6. const (
  7. NetworkInsightsNodeUnknown = "unknownNode"
  8. NetworkInsightsCloudService = "cloudService"
  9. NetworkInsightsOther = "other"
  10. NetworkInsightsInternet = "internet"
  11. NetworkInsightsSameZone = "sameZone"
  12. NetworkInsightsSameRegion = "sameRegion"
  13. )
  14. type NetworkInsightsEdge struct {
  15. Source string `json:"source"`
  16. Target string `json:"target"`
  17. Cost float64 `json:"cost"`
  18. Bytes float64 `json:"BytesInGiB"`
  19. }
  20. func NewNetworkInsightsEdge(source string,
  21. target string, cost float64, bytes float64) *NetworkInsightsEdge {
  22. return &NetworkInsightsEdge{
  23. Source: source,
  24. Target: target,
  25. Cost: cost,
  26. Bytes: bytes,
  27. }
  28. }
  29. func (nie *NetworkInsightsEdge) Key() string {
  30. return fmt.Sprintf("%s/%s", nie.Source, nie.Target)
  31. }
  32. func (nie *NetworkInsightsEdge) add(that *NetworkInsightsEdge) {
  33. nie.Cost += that.Cost
  34. nie.Bytes += that.Bytes
  35. }
  36. type NetworkInsightsNode struct {
  37. Name string `json:"name"`
  38. Type string `json:"type"`
  39. TotalEgress float64 `json:"totalEgressInGiB"`
  40. TotalIngress float64 `json:"totalIngressInGiB"`
  41. Cost float64 `json:"cost"`
  42. Internet bool `json:"internet"`
  43. SameZone bool `json:"sameZone"`
  44. SameRegion bool `json:"sameRegion"`
  45. }
  46. func NewNetworkInsightsNode(name string,
  47. networkType string, totalEgress float64, totalIngress float64, cost float64,
  48. internet, sameZone, sameRegion bool) *NetworkInsightsNode {
  49. return &NetworkInsightsNode{
  50. Name: name,
  51. Type: networkType,
  52. TotalEgress: totalEgress,
  53. TotalIngress: totalIngress,
  54. Cost: cost,
  55. Internet: internet,
  56. SameZone: sameZone,
  57. SameRegion: sameRegion,
  58. }
  59. }
  60. func (nin *NetworkInsightsNode) Key() string {
  61. if nin.Name != NetworkInsightsServiceUnknown {
  62. return nin.Name
  63. }
  64. if nin.Name == NetworkInsightsServiceUnknown && nin.Internet {
  65. return NetworkInsightsInternet
  66. }
  67. if nin.Name == NetworkInsightsServiceUnknown && nin.SameZone {
  68. return NetworkInsightsSameZone
  69. }
  70. if nin.Name == NetworkInsightsServiceUnknown && nin.SameRegion {
  71. return NetworkInsightsSameRegion
  72. }
  73. return NetworkInsightsNodeUnknown
  74. }
  75. func (nin *NetworkInsightsNode) add(that *NetworkInsightsNode) {
  76. nin.TotalEgress += that.TotalEgress
  77. nin.TotalIngress += that.TotalIngress
  78. nin.Cost += that.Cost
  79. }
  80. type NetworkInsightsGraphData struct {
  81. Nodes map[string]*NetworkInsightsNode `json:"nodes"`
  82. Edges map[string]*NetworkInsightsEdge `json:"edges"`
  83. }
  84. type NetworkInsightsGraphDataResponse struct {
  85. Nodes map[string]*NetworkInsightsNode `json:"nodes"`
  86. Edges []*NetworkInsightsEdge `json:"edges"`
  87. }
  88. func NewNetworkInsightsGraphData() *NetworkInsightsGraphData {
  89. return &NetworkInsightsGraphData{
  90. Nodes: make(map[string]*NetworkInsightsNode, 0),
  91. Edges: make(map[string]*NetworkInsightsEdge, 0),
  92. }
  93. }
  94. func (nigd *NetworkInsightsGraphData) AddNode(node *NetworkInsightsNode) {
  95. key := node.Key()
  96. if _, ok := nigd.Nodes[key]; ok {
  97. nigd.Nodes[key].add(node)
  98. } else {
  99. nigd.Nodes[key] = node
  100. }
  101. }
  102. func (nigd *NetworkInsightsGraphData) AddEdge(edge *NetworkInsightsEdge) {
  103. key := edge.Key()
  104. if _, ok := nigd.Edges[key]; ok {
  105. nigd.Edges[key].add(edge)
  106. } else {
  107. nigd.Edges[key] = edge
  108. }
  109. }
  110. func (nigd *NetworkInsightsGraphData) ToGraphDataResponse() *NetworkInsightsGraphDataResponse {
  111. if nigd == nil {
  112. return nil
  113. }
  114. nigdr := &NetworkInsightsGraphDataResponse{
  115. Nodes: nigd.Nodes,
  116. Edges: make([]*NetworkInsightsEdge, 0),
  117. }
  118. for _, edge := range nigd.Edges {
  119. nigdr.Edges = append(nigdr.Edges, edge)
  120. }
  121. return nigdr
  122. }
  123. // Converts the given NetworkInsightSetRange into the graph data to be presented.
  124. func (nisr *NetworkInsightSetRange) ToNetworkInsightsGraphData(aggregateBy []NetworkInsightProperty) (*NetworkInsightsGraphData, error) {
  125. nis, err := nisr.newAccumulation(aggregateBy)
  126. if err != nil {
  127. return nil, err
  128. }
  129. if nis == nil {
  130. return nil, err
  131. }
  132. // No graph data for empty network insight set
  133. if len(nis.NetworkInsights) == 0 {
  134. return &NetworkInsightsGraphData{}, err
  135. }
  136. data := NewNetworkInsightsGraphData()
  137. graphNodeType := ConvertNetworkInsightPropertiesToString(aggregateBy)
  138. for _, ni := range nis.NetworkInsights {
  139. // When using filtering with network insight details
  140. // if network detail set is empty dont create node and edges
  141. if len(ni.NetworkDetails) == 0 {
  142. continue
  143. }
  144. key, err := ni.Key(aggregateBy)
  145. if err != nil {
  146. return &NetworkInsightsGraphData{}, err
  147. }
  148. baseNodeCost := 0.0
  149. for _, nd := range ni.NetworkDetails {
  150. destination := nd.EndPoint
  151. // TO-DO: At this time everything will be cloud service, can be a simply if to make it like IP etc here!
  152. networkType := NetworkInsightsCloudService
  153. sameZone, sameRegion, internet := getNetworkBools(nd.TrafficType)
  154. if destination == NetworkInsightsServiceUnknown {
  155. if internet {
  156. destination = NetworkInsightsInternet
  157. }
  158. if sameZone {
  159. destination = NetworkInsightsSameZone
  160. }
  161. if sameRegion {
  162. destination = NetworkInsightsSameRegion
  163. }
  164. networkType = NetworkInsightsOther
  165. }
  166. var communicatingNode *NetworkInsightsNode
  167. var edge *NetworkInsightsEdge
  168. if nd.TrafficDirection == NetworkTrafficDirectionNone {
  169. log.Warnf("ToNetworkInsightsGraphData: unknown traffic type: %s", nd.TrafficDirection)
  170. continue
  171. }
  172. if nd.TrafficDirection == NetworkTrafficDirectionEgress {
  173. communicatingNode = NewNetworkInsightsNode(destination, networkType, 0, nd.Bytes, 0, internet, sameZone, sameRegion)
  174. edge = NewNetworkInsightsEdge(key, destination, nd.Cost, nd.Bytes)
  175. }
  176. if nd.TrafficDirection == NetworkTrafficDirectionIngress {
  177. communicatingNode = NewNetworkInsightsNode(destination, networkType, nd.Bytes, 0, 0, internet, sameZone, sameRegion)
  178. edge = NewNetworkInsightsEdge(destination, key, nd.Cost, nd.Bytes)
  179. }
  180. baseNodeCost += nd.Cost
  181. data.AddNode(communicatingNode)
  182. data.AddEdge(edge)
  183. }
  184. baseNode := NewNetworkInsightsNode(key, graphNodeType, ni.GetTotalEgressByte(), ni.GetTotalIngressByte(), baseNodeCost, false, false, false)
  185. data.AddNode(baseNode)
  186. }
  187. return data, nil
  188. }
  189. func getNetworkBools(networkType NetworkTrafficType) (sameZone bool, sameRegion bool, internet bool) {
  190. switch networkType {
  191. case NetworkTrafficTypeCrossZone:
  192. return false, true, false
  193. case NetworkTrafficTypeCrossRegion:
  194. return false, false, false
  195. case NetworkTrafficTypeInternet:
  196. return false, false, true
  197. default:
  198. log.Warnf("unknown string passed: %s defaulting to internet", networkType)
  199. return false, false, true
  200. }
  201. }