2023-11-02 19:53:41 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
|
|
|
|
package topology
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"text/tabwriter"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ComputeRelationships will analyze a full topology and generate all of the
|
2023-11-10 19:40:55 +00:00
|
|
|
// caller/destination information for all of them.
|
2023-11-02 19:53:41 +00:00
|
|
|
func (t *Topology) ComputeRelationships() []Relationship {
|
|
|
|
var out []Relationship
|
|
|
|
for _, cluster := range t.Clusters {
|
|
|
|
for _, n := range cluster.Nodes {
|
2023-11-10 19:40:55 +00:00
|
|
|
for _, w := range n.Workloads {
|
|
|
|
for _, dest := range w.Destinations {
|
2023-11-02 19:53:41 +00:00
|
|
|
out = append(out, Relationship{
|
2023-11-10 19:40:55 +00:00
|
|
|
Caller: w,
|
|
|
|
Destination: dest,
|
|
|
|
Upstream: dest,
|
2023-11-02 19:53:41 +00:00
|
|
|
})
|
|
|
|
}
|
2023-11-10 19:40:55 +00:00
|
|
|
for _, dest := range w.ImpliedDestinations {
|
2023-11-02 21:49:15 +00:00
|
|
|
out = append(out, Relationship{
|
2023-11-10 19:40:55 +00:00
|
|
|
Caller: w,
|
|
|
|
Destination: dest,
|
|
|
|
Upstream: dest,
|
2023-11-02 21:49:15 +00:00
|
|
|
})
|
|
|
|
}
|
2023-11-02 19:53:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
|
|
|
// RenderRelationships will take the output of ComputeRelationships and display
|
|
|
|
// it in tabular form.
|
|
|
|
func RenderRelationships(ships []Relationship) string {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
w := tabwriter.NewWriter(&buf, 0, 0, 3, ' ', tabwriter.Debug)
|
2023-11-10 19:40:55 +00:00
|
|
|
fmt.Fprintf(w, "CALLER\tnode\tservice\tport\tDEST\tservice\t\n")
|
2023-11-02 19:53:41 +00:00
|
|
|
for _, r := range ships {
|
2023-11-02 21:49:15 +00:00
|
|
|
suffix := ""
|
2023-11-10 19:40:55 +00:00
|
|
|
if r.Destination.Implied {
|
2023-11-02 21:49:15 +00:00
|
|
|
suffix = " (implied)"
|
|
|
|
}
|
2023-11-02 19:53:41 +00:00
|
|
|
fmt.Fprintf(w,
|
|
|
|
"%s\t%s\t%s\t%d\t%s\t%s\t\n",
|
2023-11-10 19:40:55 +00:00
|
|
|
r.callingCluster(),
|
2023-11-02 19:53:41 +00:00
|
|
|
r.Caller.Node.ID().String(),
|
|
|
|
r.Caller.ID.String(),
|
2023-11-10 19:40:55 +00:00
|
|
|
r.Destination.LocalPort,
|
|
|
|
r.destinationCluster(),
|
|
|
|
r.Destination.ID.String()+suffix,
|
2023-11-02 19:53:41 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\t\t\t\t\t\t\n")
|
|
|
|
|
|
|
|
w.Flush()
|
|
|
|
return buf.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
type Relationship struct {
|
2023-11-10 19:40:55 +00:00
|
|
|
Caller *Workload
|
|
|
|
Destination *Destination
|
|
|
|
|
|
|
|
// Deprecated: Destination
|
|
|
|
Upstream *Destination
|
2023-11-02 19:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r Relationship) String() string {
|
2023-11-02 21:49:15 +00:00
|
|
|
suffix := ""
|
2023-11-10 19:40:55 +00:00
|
|
|
if r.Destination.PortName != "" {
|
|
|
|
suffix = " port " + r.Destination.PortName
|
2023-11-02 21:49:15 +00:00
|
|
|
}
|
2023-11-02 19:53:41 +00:00
|
|
|
return fmt.Sprintf(
|
2023-11-02 21:49:15 +00:00
|
|
|
"%s on %s in %s via :%d => %s in %s%s",
|
2023-11-02 19:53:41 +00:00
|
|
|
r.Caller.ID.String(),
|
|
|
|
r.Caller.Node.ID().String(),
|
2023-11-10 19:40:55 +00:00
|
|
|
r.callingCluster(),
|
|
|
|
r.Destination.LocalPort,
|
|
|
|
r.Destination.ID.String(),
|
|
|
|
r.destinationCluster(),
|
2023-11-02 21:49:15 +00:00
|
|
|
suffix,
|
2023-11-02 19:53:41 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-11-10 19:40:55 +00:00
|
|
|
func (r Relationship) callingCluster() string {
|
2023-11-02 19:53:41 +00:00
|
|
|
return r.Caller.Node.Cluster
|
|
|
|
}
|
|
|
|
|
2023-11-10 19:40:55 +00:00
|
|
|
func (r Relationship) destinationCluster() string {
|
|
|
|
return r.Destination.Cluster
|
2023-11-02 19:53:41 +00:00
|
|
|
}
|